Skip to content

Redis 的 zset 的定义?

约 1084 字大约 4 分钟

Redis小米

2025-03-24

⭐ 题目日期:

小米 - 2024/12/26

📝 题解:

Redis 的 ZSet(Sorted Set,有序集合) 是一种结合了「集合(Set)」和「排序(Sorted)」特性的数据结构。它通过为每个成员(member)关联一个分数(score),实现成员的唯一性且按分数自动排序。以下是 ZSet 的详细解析:


1. 核心特性

  1. 成员唯一性
    • 每个成员(member)唯一,但分数(score)可以重复。
    • 若添加已存在的成员,会更新其分数并重新排序。
  2. 按分数排序
    • 默认按分数升序排列,支持按分数范围快速查询。
  3. 高性能操作
    • 插入、删除、查询的时间复杂度为 O(log N)(N 为成员数量),接近平衡树的效率。

2. 底层实现

ZSet 的底层采用两种数据结构,根据数据量动态切换:

(1) 压缩列表(Ziplist)

  • 适用条件
    • 成员数量 ≤ zset-max-ziplist-entries(默认 128)。
    • 成员长度 ≤ zset-max-ziplist-value(默认 64 字节)。
  • 特点
    • 内存紧凑,所有成员和分数连续存储。
    • 适合小规模数据,节省内存。

(2) 跳跃表(Skiplist) + 哈希表(Hash Table)

  • 跳跃表
    • 多层链表结构,支持快速范围查询和排名操作。
    • 每个节点包含多个指针,实现类似二分查找的效果。
  • 哈希表
    • 用于快速定位成员及其分数(时间复杂度 O(1))。
  • 协同工作
    • 跳跃表负责排序和范围操作。
    • 哈希表负责快速查找成员的分数。

3. 常用命令

命令作用示例
ZADD key score member添加/更新成员及其分数ZADD leaderboard 1000 "Alice"
ZRANGE key start stop按升序返回指定排名范围的成员ZRANGE leaderboard 0 2 WITHSCORES
ZREVRANGE按降序返回指定排名范围的成员ZREVRANGE leaderboard 0 2 WITHSCORES
ZRANK key member获取成员升序排名(从0开始)ZRANK leaderboard "Alice"
ZREVRANK获取成员降序排名ZREVRANK leaderboard "Alice"
ZSCORE key member获取成员的分数ZSCORE leaderboard "Alice"
ZRANGEBYSCORE按分数范围返回成员(支持分页)ZRANGEBYSCORE leaderboard 800 1200
ZREM key member删除指定成员ZREM leaderboard "Bob"
ZCOUNT统计分数范围内的成员数量ZCOUNT leaderboard 800 1200
ZCARD获取集合成员总数ZCARD leaderboard

4. 典型应用场景

(1) 排行榜(Leaderboard)

  • 示例:游戏玩家积分实时排序。
  • 操作
    • 更新分数:ZADD leaderboard 1500 "PlayerA"
    • 获取前10名:ZREVRANGE leaderboard 0 9 WITHSCORES
    • 查询玩家排名:ZREVRANK leaderboard "PlayerA"

(2) 延迟队列

  • 示例:定时任务调度。
  • 操作
    • 添加任务:ZADD tasks <执行时间戳> "task_data"
    • 轮询到期任务:ZRANGEBYSCORE tasks 0 <当前时间戳> LIMIT 0 1

(3) 范围统计

  • 示例:统计某时间段内的用户行为。
  • 操作
    • 按时间戳存储事件:ZADD events 1625000000 "login"
    • 查询特定时间段的事件:ZRANGEBYSCORE events 1625000000 1626000000

(4) 优先级队列

  • 示例:任务按优先级处理。
  • 操作
    • 插入任务:ZADD jobs 1 "low_priority_task"
    • 获取最高优先级任务:ZRANGE jobs 0 0

5. 高级功能

(1) 集合运算

  • ZUNIONSTORE / ZINTERSTORE:合并或交集多个 ZSet。
  • 注意:运算复杂度较高,可能阻塞 Redis,慎用于大数据量场景。

(2) 分数递增

  • ZINCRBY key increment member:为成员的分数增加指定值。
    ZINCRBY leaderboard 50 "Alice"  # Alice 分数增加50

6. 性能与内存优化

  1. 控制数据规模
    • 避免单个 ZSet 存储过多成员(如百万级),可能引发性能下降。
  2. 合理选择编码
    • 调整 zset-max-ziplist-entrieszset-max-ziplist-value,平衡内存与性能。
  3. 避免大范围查询
    • ZRANGE key 0 -1 可能阻塞 Redis,需分页操作。

7. 注意事项

  • 分数精度:分数为双精度浮点数,可能存在精度丢失问题。
  • 字典序排序:若分数相同,按成员字符串的二进制顺序排序。
  • 内存占用:跳跃表结构的内存开销较大,需监控内存使用。

8. 总结

ZSet 是 Redis 中最灵活的数据结构之一,适用于需要排序和范围操作的场景。其底层通过 跳跃表 + 哈希表 的混合设计,兼顾了查询效率和排序功能。在使用时,需结合具体业务需求,合理设计分数规则,并关注性能与内存的平衡。