https://chat.deepseek.com/share/iqv63ua6g2tvbsk7a0
题目:Redis中的Zset是怎么实现的?
难度:medium
评分:⭐⭐⭐⭐☆☆(3/5)
redis 中 zset 是有序集合,在底层有两组实现一个是小批量数据的压缩列表,一个是大量数据后的跳跃表;小批量数据到时候,直接按照分数信息进行集合顺序插入到压缩列表中,读取数据的时候遍历压缩列表;当数据量比较大了之后,使用跳跃表实现 zset 有序集合,基于分数构建多层级大跳跃表,每一层级都类似二分的方式去找到下一层级中的一个位置,逐层的快速找到最底层目标数据
优点:
两种底层编码抓到- 跳跃表多层级定位机制描述基本对
不足:
❌ 编码是二选一非递进:ziplist/listpack vs skiplist 是编码切换- ❌ 5.0+ ziplist 已被 listpack 完全替代- ❌ 跳跃表节点还挂哈希表(O(1) member→score)- ❌ 遗漏编码切换阈值:zset-max-listpack-entries=128 / zset-max-listpack-value=64- ⚠️ 跳跃表描述"二分"不准确,是跳级定位不是二分
核心考点:考察对 Zset 底层编码切换机制的理解,区分"编码二选一"和"递进升级"。
知识点拆解:
关键命令复杂度:
面试官您好,Zset 有两种底层编码,是二选一关系,不是递进升级。
小数据用 listpack(Redis 5.0+ 替代了 ziplist),连续内存块,内存紧凑。大数据用 skiplist + hashtable 组合。
编码切换阈值是两个:zset-max-listpack-entries(默认 128 个元素)和 zset-max-listpack-value(默认 64 字节)。任一超过就切换到 skiplist。
skiplist 是多层级跳跃表,底层 O(n),顶层 O(1),跳级定位到目标节点。每个节点还挂一个哈希表,通过 member 查找 score 是 O(1)。
ZADD/ZSCORE/ZREMRANGEBYSCORE 在 listpack 上 O(n),在 skiplist 上 O(log n)。ZRANGE 在 skiplist 上 O(log n + m),m 是返回元素数。
编码切换不可逆——一旦切换到 skiplist,即使元素数减少也不会回退 listpack,避免频繁切换的开销。
为什么不用 B+ 树?B+ 树节点大、内存浪费、实现复杂;跳跃表内存紧凑、实现简单、插入删除效率高。Redis 选跳跃表是性能和复杂度的平衡。