Skip to content

Redis Zset(有序集合)

概述

Zset是Redis中一种特殊的数据结构,它在Set的基础上为每个元素关联了一个分数(score),使得元素可以按照分数进行排序。

底层实现

编码方式

Zset支持两种底层实现:

  1. ziplist(压缩列表)

    • 元素数量 < 128 且 每个元素 < 64字节
    • 优点:内存紧凑
    • 缺点:插入/删除O(N)
  2. skiplist + dict(跳表 + 哈希表)

    • 元素数量 >= 128 或 有元素 >= 64字节
    • 优点:查找/插入O(logN)
    • 缺点:内存开销较大

数据结构

c
// Redis源码中的zset结构
typedef struct zset {
    dict *dict;      // 哈希表,O(1)查找元素
    zskiplist *zsl;  // 跳表,按score有序
} zset;

跳表原理

Level 3: [head] -----> [node5: score=90] ----------------------> [NULL]
Level 2: [head] -> [node2: score=20] -> [node5: score=90] -> [NULL]
Level 1: [head] -> [node1: score=10] -> [node2: score=20] -> [node3: score=50] -> [node5: score=90] -> [NULL]
Level 0: [head] -> [node1] -> [node2] -> [node3] -> [node4] -> [node5] -> [NULL]

跳表本质是多层链表,最高32层,每层是原链表的有序子集。

常用命令

基本操作

bash
# 添加元素
ZADD mykey 100 member1  # 添加单个
ZADD mykey 100 member1 200 member2 300 member3  # 批量添加

# 获取分数
ZSCORE mykey member1

# 获取排名(从0开始,score升序)
ZRANK mykey member1
ZREVRANK mykey member1  # 倒序排名

# 分数范围查询
ZRANGEBYSCORE mykey 100 200  # 升序
ZREVRANGEBYSCORE mykey 200 100  # 降序

# 元素数量
ZCARD mykey

# 分数范围元素数量
ZCOUNT mykey 100 200

有序集合操作

bash
# 获取元素(带分数)
ZRANGE mykey 0 -1 WITHSCORES

# 交集
ZUNIONSTORE dest 2 key1 key2

# 并集权重
ZUNIONSTORE dest 2 key1 key2 WEIGHTS 1 2

# 交集
ZINTERSTORE dest 2 key1 key2

面试考点

Q1: Zset为什么用跳表而不是红黑树?

答案

  1. 跳表实现更简单,代码可读性好
  2. 范围查询(ZRANGE)更高效:O(logN + M),红黑树需要O(logN + M)
  3. 跳表插入不需要旋转,比红黑树更简单
  4. 内存利用率更高:平均每个节点1.33个指针

Q2: Zset如何实现排名计算?

答案

  • 使用ZRANK命令,从跳表中找到元素在第几层
  • 沿搜索路径向下累加rank
  • 时间复杂度O(logN)

Q3: Zset的ziplist转skiplist条件?

答案

  • 元素数量 >= 128
  • 或 任意元素长度 >= 64字节

Q4: Zset的应用场景?

答案

  1. 排行榜(游戏排行榜、热门文章)
  2. 延时队列(按时间戳排序的任务)
  3. 权重队列(带权重的任务调度)
  4. 分布式锁(带过期时间的锁)

最后更新: