Redis7--ziplist的替代者listpack
转自公众号Redis开发运维实战
一、ziplist简介
ziplist是一种连续内存空间并且有序的压缩链表,其主要的数据结构如下图:
结合以上数据结构的内存模型图,我们可以看出ziplist具有的一些优势与问题:
二、listpack简介
由于ziplist存在不可避免的问题 -- 连锁更新问题, 所以在Redis 5版本中,推出了ziplist替代版本listpack。
1. ziplist整体的结构与listpack的整体结构对比
从以上整体的对比图可以看到,其实两者结构相差不大,listpack相对于ziplist,没有了指向末尾节点地址的偏移量,这样也可以解决ziplist内存长度限制的问题。
2. entry结构对比
其数据结构对比如下图:
从以上结构中可以看到,listpack移除了prevlen,在data后新增了backlen,两者有着本质区别:
● 在ziplist中,prevlen代表前一个entry节点长度的偏移量;
● 在listpack中,backlen代表的是本entry节点的回朔起始地址长度的偏移量
Entry这样设计具有以下一些优势:
● 在遍历最后一个entry时可以通过lp+totallen快速定位到lp尾地址,然后使用backlen快速定位到last entry的起始地址;***并且可以将head中的last offset字段节省出来;
● 由于backlen仅代表了回朔本entry起始地址长度的偏移量,所以在增/删/改时,无需再关心前一个节点的长度,仅需要整体移动entry即可,所以不会涉及到内存的连锁更新;具体的代码流程这里不再复述;
三、listpack替换quicklist收益
1. list相关命令性能对比(quicklist with ziplist -> quicklist with listpack)
从以上结果可以看到,lpush/rpush/lpop/rpop性能略有提升,这得益于listpack避免了连锁更新的问题,符合预期;但是lrange性能下降是因为在lpNext与lpGet函数中需要计算整个entry的长度(包括计算data长度与backlen)以及进行有效性验证,在代码逻辑上相较于ziplistNext/ziplistGet要复杂一些。
2. hash/zset类命令性能影响
由于hash与zset类命令,具有两种编码模式,默认为ziplist,在entry个数达到配置的默认值时,会将数据结构分别转换为hash与skiplist,所以在entry个数较少时,性能影响不大;entry个数越长、变更更频繁,新版本会具有更好的性能,而且在实际业务场景中,这个值都不会被配置的很大,所以这里也不再测试,仅从理论上推测性能影响。
3. 关于RDB的性能影响
由于ziplist和listpack都是一段连续的内存,所以在写入和加载上,性能不会有明显的差异。
4. RDB加载时ziplist转换为listpack时的耗时
低版本的RDB在redis7中加载时,会自动将ziplist转换为listpack,其整体加载耗时会大约增加 9%-54% 左右。
具体耗时结果如下:
● List(38%-46%)
● hash (29%-54%)
● Zset (9%-16%)
四、ziplist替换为listpack后带来的连锁变更
1. 相关配置变更
* 新增list-max-listpack-size, 是list-max-ziplist-size的别名;
* 新增hash-max-listpack-entries, 是hash-max-ziplist-entries的别名;
* 新增hash-max-listpack-value, 是hash-max-ziplist-value的别名;
* 新增zset-max-listpack-entries, 是zset-max-ziplist-entries的别名;
* 新增zset-max-listpack-value, 是zset-max-ziplist-value的别名;
由于新增配置均是别名,所以原有针对ziplist的相关配置,均可在redis7中自动生效,无需再做配置修改。
2. RDB相关
● RDB类型新增
◆ RDB_TYPE_HASH_LISTPACK
◆ define RDB_TYPE_ZSET_LISTPACK
◆define RDB_TYPE_LIST_QUICKLIST_2
●版本号提升至 10
由于RDB类型和版本号的变更,所以需要更新迁移工具,解析并支持新的类型。
五、参考链接
1、listpack migration -- https://github.com/redis/redis/issues/8702
2、replace ziplist with listpack in quicklist -- https://github.com/redis/redis/pull/9740/
3、Replace all usage of ziplist with listpack for t_hash --
https://github.com/redis/redis/pull/8887
4、Replace all usage of ziplist with listpack for t_zset --
https://github.com/redis/redis/pull/9366
文章转自公众号:Redis开发运维实战