zset = 跳表(skiplist) + 哈希表(dict),两套结构同时保存一份数据。
数据特点:成员member唯一不重复,每个member绑定一个分数score,按照score排序。
1. 两个底层结构各自职责
- skiplist 跳表
- 按照
score做排序,负责:范围查询、排行榜、倒序、区间分页(zrange、zrevrange、zrangebyscore) - redis的跳表是双向跳表,节点带有back指针,可以高效反向遍历。
- 平均增删改查 o(log n),最大层数固定32层,节点层数随机生成。
- dict 哈希表
- key:member成员,value:对应的score分数
- 作用:o(1)时间快速获取某个member的score,判断成员是否存在,保证member唯一性。
插入的时候dict先判断member是否已经存在,实现去重。
⚠️两份结构存的是同一份数据,内存会有少量额外开销,换取查询性能。
2. ziplist 压缩列表(小zset)
当满足两个条件,zset不使用跳表,改用ziplist压缩列表存储:
- 元素数量 <
zset‑max‑ziplist‑entries默认128 - 每个元素大小 <
zset‑max‑ziplist‑value默认64字节
ziplist是连续内存,节约内存;内部按score有序排列。
一旦超过阈值,自动转换为 skiplist + dict。
3. 核心命令底层怎么走
zadd key score member- dict判断member是否存在,存在则更新score;不存在新增
- 将数据插入跳表,按score维护有序
zscore key member:直接查dict哈希表,o(1)返回分数,不走跳表zrange key start end:直接在skiplist做范围遍历 o(log n + k),k是返回元素数量
4. 业务场景
- 排行榜、热搜、延时队列、带权重的有序列表
面试常见坑
- score可以相同:多个member允许分数一样;score相同会按member字典序排序。
- zset没有给member单独过期的能力,只能对整个zset key设置expire。
- 不要存超大zset,
zrange返回大量数据会阻塞redis。
总结:
zset底层分两种情况,少量短元素用ziplist压缩列表;数据量大则采用跳表+哈希表组合。跳表负责排序和范围查询,哈希表实现快速取score和去重。
口述简短版:
redis的zset,数据少的时候用压缩列表。数据量大是跳表加上哈希表一起实现。跳表负责按照score排序,用来做排行榜、范围查询;哈希表用来快速拿到成员的分数,保证成员不重复。注意成员唯一,分数可以重复。
拓展:zset 是什么,和 set 有什么区别
zset 全称 sorted set(有序集合),是 redis 五种核心数据类型之一。它在普通 set 的基础上增加了一个 score(分数)参数,让集合中的元素能按分数自动排序 。
- 核心特性:
- 元素唯一性:和 set 一样,同一个元素在 zset 中只能出现一次。
- 自动排序:元素按 score 从小到大排列,score 相同时按字典序排序。
- 分数可重复:不同元素可以有相同的 score 值。
- 底层实现:小数据量用 listpack(redis 7.0+)或 ziplist,大数据量用跳表 + 哈希表。
- 与 set 的关键区别:
- set 是无序集合,zset 是有序集合。
- set 只存元素,zset 存元素 + 分数。
- set 适合去重存储,zset 适合排行榜等排序场景。
到此这篇关于redis zset的实现原理详解的文章就介绍到这了,更多相关redis zset原理内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论