《Redis核心技术与实战》学习总结(2)

fd2ba6cd105c72a3002ea0676266d6d9.gif

【Redis| 总结/Edison Zhou

1上一篇的遗留问题

上一篇总结了一个KV数据库的基本架构 和 Redis的底层数据结构概览,重点总结了Sorted Set的两个数据结构的切换,但没有介绍List的两个数据结构的切换,因此本文试着总结一下。

这里先直接给出答案:

c585da406902c9cd88fe2895b4e4f37a.png

从上图可以看到,当List的数据满足下面两个条件时,就会使用压缩列表,否则使用双向链表。

(1)列表对象保存的所有字符串元素的长度都小于64字节;

(2)列表对象保存的元素数量小于512个;

这两个参数其实也是可以在redis.conf中修改的:

list-max-ziplist-value 64 
list-max-ziplist-entries 512

2Redis 3.2之前的实现

由上一篇已经知道,List类型的底层实现包括了 双向链表 和 压缩列表,但这是在Redis的3.2版本之前的底层实现。而从Redis 3.2版本开始,Redis修改了List的底层实现,将压缩列表 和 双向链表 结合,我们称它为 quickList 快速列表。

56ea66701d48dd3d7bf347fe593bcebf.png

从第一节的内容我们已经知道,当创建一个新的List时,Redis会优先使用压缩列表,然后在有需要的时候,再转成双向链表

Redis为什么要这么设计呢?

因为,双向链表的内存占用 比 压缩列表 多,而压缩列表的设计初衷就在于 节约内存。众所周知,Redis之所以快的原因之一就是它是内存数据库,所有操作都在内存上完成,因此对于内存的占用有要求。

932e3671e53d41c13da6fee592c90a33.png

双向链表

05901097ad330a480861c9bcc28ab5a8.png

压缩列表

画外音:在Redis 3.2 之前,我们也可以通过命令来验证:

192.168.80.100:6379> rpush testkey "edison" "andy" "leo"
3
192.168.80.100:6379> object encoding testkey
ziplist
192.168.80.100:6379> rpush testkey "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
4
192.168.80.100:6379> object encoding testkey
linkedlist

那么,压缩列表为什么占用内存少呢?

其实从上面的图和下面的源码也可以看出来,压缩列表并没有维护双向指针prev 和 next,而只是存储了上一个entry的长度 和 下一个entry的长度,通过长度来推算下一个entry在哪里。

typedef struct zlentry {    // 压缩列表节点unsigned int prevrawlensize, prevrawlen;    // prevrawlen是前一个节点的长度,prevrawlensize是指prevrawlen的大小,有1字节和5字节两种unsigned int lensize, len;  // len为当前节点长度 lensize为编码len所需的字节大小unsigned int headersize;    // 当前节点的header大小unsigned char encoding; // 节点的编码方式unsigned char *p;   // 指向节点的指针
} zlentry;

这是一种典型的“时间换空间”的方法,即牺牲读取的性能,换取极致的存储空间。由于压缩列表存储在一段连续的内存上,所以它的存储效率还是蛮高的。

但是,此种设计只适合在字段个数、值比较小的时候,一旦长度过长,压缩列表的设计(利于读取但不利于修改的初衷)会导致修改和删除操作需要频繁的申请和释放内存,可能会导致大量的数据拷贝,拖慢Redis的整体性能

因此,Redis选择了在达到阈值时,切换数据结构为双向链表。

3Redis 3.2之后的实现

在Redis 3.2及之后,Redis选择了结合压缩列表 和 双向链表的优点,形成了一个新的底层实现:quicklist 快速列表。

快速列表是一个压缩列表组成的双向链表,每个节点使用压缩列表来保存数据。换句话说,快速列表中保存了一个个小的压缩列表。其结构如下图所示:

6a8bfe551b8fc1d1eb065fa4660cc482.png

为了进一步节约空间,Redis 还会对压缩列表进行压缩存储(一种无损压缩算法LZF),这取决压缩深度的参数设置,我们可以选择不压缩(默认值不压缩) 也可以 选择压缩中间节点。

画外音:两端节点一般不被压缩,因为当一个链表很长时,最频繁访问的就是两端的数据,根据“二八定律”,两端数据不压缩,而将中间数据压缩,从而节省空间,但又保证读取效率。

此外,对于每个压缩列表的大小,也是可以通过在redis.conf中的参数来设置的:

list-max-ziplist-size -2

参数可选值从-1到-5,其含义如下:

1) -5:每个quicklist节点上的ziplist大小不能超过64kb。

2) -4:每个quicklsit节点上的ziplist大小不能超过32kb。

3) -3:每个quicklsit节点上的ziplist大小不能超过16kb。

4) -2:每个quicklsit节点上的ziplist大小不能超过8kb。

5) -1:每个quicklsit节点上的ziplist大小不能超过4kb。

画外音:在Redis 3.2 之后,我们也可以通过命令来验证:

192.168.80.100:6379> rpush testkey "edison" "andy" "leo"
3
192.168.80.100:6379> object encoding testkey
quicklist
192.168.80.100:6379> rpush testkey "wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww"
4
192.168.80.100:6379> object encoding testkey
quicklist

综述,快速列表的本质其实是对压缩列表的一次封装,使用小块的压缩列表来组织,既可以保证内存占用较小,也可以保证操作性能

End总结

本文总结了Redis的List类型在何时使用压缩列表,何时使用双向链表,以及快速列表的基本概念。当然,更多的内容还是需要自行去搜索学习,意犹未尽的童鞋也可以去分析源码。最后,如果你对其他集合类型也有此类问题,你可以参考下面附录中的内容,而至于Why,则可以自行百度搜索了解。

Anyway,对于Redis集合类型的底层思想采用了两种数据结构的设计思想是值得我们学习借鉴的,它其实充分体现了软件设计中的Tradeoff(权衡)思想。对于Redis来说,即在主体目标是保证性能的大约束前提下,权衡多方因素如操作时间和空间占用,以达到较为稳定的运行表现。对于软件设计来说,也需要在时间 vs 空间,新技术 vs 老技术,优雅 vs 效率,轻度设计 vs 重度设计等之间做权衡,一个问题总会有多种解决方案可以实现,在特定的时间段,永远没有最完美的设计,只有较合适的设计。在实际中,它可能结合了多种因素的考虑,不断地去粗取精,迭代为更好的设计。

Ref附录

Hash:

29d48a72ec427eb545f08ff594cc0e74.png

Set:

864f2670a546517c22c58c351bf4385a.png

Sorted Set(zset):

1b2c2356caecc2c7515d41bfdf9f5baa.png

参考资料

极客时间,蒋德钧《Redis核心技术与实战》

68a567d4d1c3125710b4c58264f39788.gif

年终总结:Edison的2020年终总结

数字化转型:我在传统企业做数字化转型

C#刷题:C#刷剑指Offer算法题系列文章目录

.NET面试:.NET开发面试知识体系

.NET大会:2020年中国.NET开发者大会PDF资料

fd8abe61b28d4159b6afdf50025e2e0e.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296606.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】sqlserver游标概念与实例全面解说

引言 我们先不讲游标的什么概念,步骤及语法,先来看一个例子: 表一 OriginSalary 表二 AddSalary 现在有2张表,一张是OriginSalary表--工资表,有三个字段0_ID 员工…

洛谷2296 寻找道路

题目描述 在有向图G 中,每条边的长度均为1 ,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件: 1 .路径上的所有点的出边所指向的点都直接或间接与终点连通。 2 .在满足…

奇迹mu选区后就一直显示连接服务器,奇迹mu双开

《奇迹mu》双开方法 EX702双开的方法,今天小编为大家带来了奇迹MU双开方法,为大家解决一些双开中的问题,下面就一起来看看EX702双开的问题吧!奇迹mu双开:接下来是这样:1、 复制2个客户端,放在不…

第十一章:【UCHome二次开发】功能修改

有些功能的修改涉及到了流程或数据需求的变动,这时候简单的修改模板文件已经无法解决问题,而是需要修改对应的流程和数据处理代码来完成。一般处理程序文件位于/source文件夹下。具体的代码修改就是根据功能逻辑来调整php代码或是sql语句,这里…

华为鸿蒙OS 2.0正式发布!明年华为手机将全面支持!

全世界只有3.14 % 的人关注了爆炸吧知识9 月 10 日,在华为开发者大会 2020 上,华为消费者业务 CEO 余承东宣布推出鸿蒙 OS 2.0 版本(HarmonyOS 2.0)。鸿蒙 OS 的代码也在今天下午HDC 2020 大会结束后的 18:18 正式开放。鸿蒙 OS 开…

微软认真聆听了开源 .NET 开发社区的炮轰: 通过CLI 支持 Hot Reload 功能

微软近日激怒了开源.NET社区,起因是它删除了开源.NET的一项旗舰功能,以提升Visual Studio 的吸引力,尤其是针对与Visual Studio颇有渊源的跨平台源代码编辑器Visual Studio Code。好消息是微软听取了社区的声音,恢复了通过CLI支持…

烽火服务器查询服务器型号,烽火服务器应该起的进程

烽火服务器应该起的进程 内容精选换一换IDE Daemon模块提供接口给Matrix和Framework调用,Matrix通过这些接口可以实现将DVPP预处理结果数据发送到IDE-daemon-hiai进程所在的服务器,IDE-daemon-hiai将结果数据写到文件中;Framework通过调用这些…

(译)元素浮动的那些事儿

原文:http://bitsofco.de/2015/how-floating-works/,作者 Ire Aderinokun 发表于 2015 年 8 月 11 日。 尽管我们现在用浮动布局已经很少了,但是在一些特殊的需求下,它仍然是唯一可行的解决方案。在这些少见的需求中,浮…

无法定位程序输入点dxgiget_美国ABB TZIDC 智能定位器调试方法

一、ABBTZID-C 智能定位器安装及操作气路连接使用与定位器气源端口处标识的标准接口连接气源连接定位器的输出与气动执行器的气缸电气连接根据下列接线端子图以及设计要求进行相应的配线(一般只需11,-12,31,-32)11-12控制信号输入端子(DC4---…

这个黑科技小音箱,不用连蓝牙、一触即播

▲ 点击查看以前用蓝牙音箱,都要打开蓝牙找半天,有时还找不到对应的音箱。找到了,连接又很 …… 漫长 ……一句「请等待蓝牙配对」重复好几遍还没连上,整个人都不好了。而今天介绍的这个开物灵犀感应音箱,不用连蓝牙&a…

Win11运行安卓超详细教程!芜湖起飞!

一、前提Windows 11 版本号为 Build 22000.xxx 或更高版本。您的电脑硬件 BIOS/UEFI 支持虚拟化功能。二、支持本教程适用于 Windows 11 正式版和预览版,包括 Dev 频道、Beta 频道和 Release Preview 频道。本教程适用于搭载 Intel 和 AMD 等处理器的 Windows 11 电…

精品教程--Android实战系列源码与教程

下载源码 知识技能概要: 1. 此套为零基础源码与教程 2. 包括了Android应用开发所有技术 3. 配套2011QQ效果实现项目源码 4. 堪称最详细中文源码注释 ...... 详细介绍: 1. 零基础源码与教程 本套源码与教程,由我们具有丰富开发经验的高级程师针对需要学习…

mdx 聚合函数

聚合函数Aggregation(set_express, numeric_express), Aggregation(http://msdn.microsoft.com/zh-cn/library/ms145524.aspx)执行求和函数, 如果和某些其他求和函数配合的话, 会有变化. 看一个例子 SELECT { ([Measures].[Reseller Sales Amount]), ([M…

被小学数学题套路到哭!这些“逆天”题目,谁做谁知道…

全世界只有3.14 % 的人关注了爆炸吧知识看着孩子的作业题,有多少爸爸妈妈感叹着,幸亏自己毕业早,要不然小学都不能毕业!这不,最近一道简单的小学数学题,又刷爆了家长们的朋友圈。一起往下看。算一算图中的这…

ASP.NET性能优化之构建自定义文件缓存

ASP.NET的输出缓存(即静态HTML)在.NET4.0前一直是基于内存的。这意味着如果我们的站点含有大量的缓存,则很容易消耗掉本机内存。现在,借助于.NET4.0中的OutputCacheProvider,我们可以有多种选择创建自己的缓存。如&…

《Redis核心技术与实战》学习总结(1)

【Redis】| 总结/Edison Zhou0写在开头作为Key/Value键值数据库,Redis的应用非常广泛。在之前多年的工作生涯中,我也只是关注了零散的技术点,没有对Redis建立起一套整体观,但只有建立了系统整体观,才能更好地定位问题和…

饿了么翻车,美团被质疑,马云也赔了40亿,这项技术为什么让人害怕?

全世界只有3.14 % 的人关注了爆炸吧知识人类还没用力AI可能就倒下了8日,一篇《外卖骑手,困在系统里》的文章刷爆了朋友圈。看过的人多半都不好受,除了作为社畜感叹生活不易外,就是感叹外卖系统的AI算法对人类的裹挟是那么的残酷。…

如何强制 .NET 程序以 管理员模式 运行 ?

咨询区 Gold:我有一个 winform 程序部署客户的PC机上,请问我如何通过编码的形式强制让程序以管理员模式运行?回答区 Gaspa79:如果你用的是 Visual Studio 2019,可以通过工具去配置,右键 项目 -> 新建项 …

bitmap 转byte[]后读取_闲谈redis的bitmap

bitmap的原理bitmap就是通过最小的单位bit(8bit 1b 0.001kb)来进行0或者1的设置,表示某个元素对应的值或者状态。一个bit的值,或者是0,或者是1;也就是说一个bit能存储的最多信息是2。优点基于最小的单位bit进行存储,…

序1--年轻正当时(特权)

序1 年轻正当时 这本所谓的书,恐怕不一定能够带还没入门的U杀进FPGA开发的大门,当然也肯定不能达到进阶的目的。但是,姑且应了Bingo老弟所谓的对“图像的直觉”,确实图文并茂的从某一个山寨面把FPGA开发赤裸裸的展现给了大家。 被…