主题
面试速答(先看这里)
**一句话结论:**在Redis 7.0之前,ZSet主要靠ZipList和 SkipList 实现 。
60秒标准回答:
之所以把他们三个放在一起比较,主要是因为他们都是实现ZSet的主要数据结构
在Redis 7.0之前,ZSet主要靠ZipList和 SkipList 实现 。而在Redis 7.0开始,ZipList已经被ListPack给替代了,也就是说 Redis 7.0之后,ZSet主要靠ListPack和SkipList实现
这里SkipList是一直在的,先介绍他
**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点
回答主线:
- **SkipList:**SkipList就是跳表。
- **ListPack:**ListPack是 Redis 在 5.0 版本引入的一种新的内存高效数据结构(在Redis 7.0正式替代ZipList用在ZSet中),它是为了解决 ziplist 和 skiplist 在一些场景下的不足而提出的。
**记忆锚点:**ZipList → SkipList → ListPack → Redis → ZSet → log
关键取舍:
- listpack 是一种 适用于小型有序集合、列表和哈希的压缩数据结构 ,它比 ziplist 更加灵活、适应性更强,并且提供了对大数据量的更好支持。
易错提醒:
- 更重要的事,ListPack通过创新的数据结构方案,避免了级联更新的问题。
- 而且,因为ZipList的结构导致了,它在极端情况下可能会出现一种级联更新的问题: 所以就有了ListPack ListPack ListPack是 Redis 在 5.0 版本引入的一种新的内存高效数据结构(在Redis 7.0正式替代ZipList用在ZSet中),它是为了解决 ziplist 和 skiplist 在一些场景下的不足而提出的。
加分表达:
- 但是ZipList也有缺点,正因为他是紧凑的线性结构,所以如果在 ZipList 中查找一个元素时,可能需要遍历整个列表,同理插入和删除操作也是线性的。
追问准备:
- 围绕「ZipList」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「SkipList」:底层原理是什么?使用时有哪些边界和常见坑?
- 围绕「ListPack」:底层原理是什么?使用时有哪些边界和常见坑?
- 如果线上出现异常,你会如何定位、验证并规避?
典型回答
之所以把他们三个放在一起比较,主要是因为他们都是实现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?
打开文档:✅ZSet为什么在数据量少的时候用ZipList,而在数据量大的时候转成SkipList?
而且,因为ZipList的结构导致了,它在极端情况下可能会出现一种级联更新的问题:
打开文档:✅介绍下Redis中的ZipList和他的级联更新问题
所以就有了ListPack
ListPack
ListPack是 Redis 在 5.0 版本引入的一种新的内存高效数据结构(在Redis 7.0正式替代ZipList用在ZSet中),它是为了解决 ziplist 和 skiplist 在一些场景下的不足而提出的。
listpack 是一种 适用于小型有序集合、列表和哈希的压缩数据结构,它比 ziplist 更加灵活、适应性更强,并且提供了对大数据量的更好支持。
更重要的事,ListPack通过创新的数据结构方案,避免了级联更新的问题。
📄 ✅Redis中的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 | 全类型小规模存储 |