✅Redis的ZipList、SkipList和ListPack之间有什么区别?

✅Redis的ZipList、SkipList和ListPack之间有什么区别?

典型回答

之所以把他们三个放在一起比较,主要是因为他们都是实现ZSet的主要数据结构。

✅Redis中的Zset是怎么实现的?

在Redis 7.0之前,ZSet主要靠ZipList和SkipList实现。而在Redis 7.0开始,ZipList已经被ListPack给替代了,也就是说Redis 7.0之后,ZSet主要靠ListPack和SkipList实现。


这里SkipList是一直在的,先介绍他。

SkipList

SkipList就是跳表。跳表是一种在链表的基础上增加多层索引的结构。跳表的结构通过多层索引链表来提高查找效率,相比于传统的链表,它能够在对数时间内完成元素的查找、插入和删除。

跳表的优势就是插入、删除、查找操作都可以在 O(log N) 的时间复杂度内完成。并且支持高效的范围查询,如 **ZRANGEBYSCORE****ZRANGE**** 等。**

但是跳表有个缺点,那就是他的数据结构决定了他的内存占用更高。每个元素有多个指针来维护多层链表,导致内存开销更大。

ZipList

而ZipList是一个压缩的数据结构,它的每个元素都是连续存储的,因此内存的使用非常紧凑。与其他数据结构相比,ZipList在小规模数据存储时显著减少了内存占用。

但是ZipList也有缺点,正因为他是紧凑的线性结构,所以如果在 ZipList 中查找一个元素时,可能需要遍历整个列表,同理插入和删除操作也是线性的。所以ZipList的插入、删除和查找操作的时间复杂度通常是 O(N)。相对来说是比较慢的。

这也是为什么Redis会在元素数量比较少的时候用ZipList,而在数据量大了之后转成SkipList的原因。

✅ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList?

而且,因为ZipList的结构导致了,它在极端情况下可能会出现一种级联更新的问题:

✅介绍下Redis中的ZipList和他的级联更新问题

所以就有了ListPack

ListPack

ListPack是 Redis 在 5.0 版本引入的一种新的内存高效数据结构(在Redis 7.0正式替代ZipList用在ZSet中),它是为了解决 ziplistskiplist 在一些场景下的不足而提出的。

listpack 是一种 适用于小型有序集合、列表和哈希的压缩数据结构,它比 ziplist 更加灵活、适应性更强,并且提供了对大数据量的更好支持。

更重要的事,ListPack通过创新的数据结构方案,避免了级联更新的问题。

✅Redis中的ListPack是如何解决级联更新问题的?

对比总结

特性 SkipList (跳表) ZipList (压缩列表) ListPack (紧凑列表)
设计目标 高效范围查询和有序访问 内存紧凑,减少碎片 解决级联更新问题
内存布局 多层链表结构 连续内存块 连续内存块
查询复杂度 O(log N) O(n) O(n)
插入复杂度 O(log N) O(1)~O(n²) (级联更新) O(1) (无级联更新)
删除复杂度 O(log N) O(1)~O(n²) (级联更新) O(1) (无级联更新)
内存占用 高 (有指针开销) 极低
版本支持 所有版本 Redis ≤6.2 Redis ≥5.0 (7.0+默认)
核心优势 高效有序访问 小数据内存优化 无级联更新+内存紧凑
主要缺点 内存占用高 级联更新 范围查询效率低
应用场景 有序集合(ZSet) 小规模Hash/Set/ZSet 全类型小规模存储