ZSET 数据结构

新需求:排行榜

产品经理又来了:

【需求文档】排行榜功能

功能 1:热门文章榜
- 按点赞数排序
- Top 100
- 实时更新

功能 2:24 小时热榜
- 最近 24 小时发布文章
- 按点赞数排序

功能 3:本周热榜
- 本周发布文章
- 按点赞数排序

功能 4:作者榜
- 按文章获赞总数
- Top 100 作者

这就是排行榜需求。

ZSET 简介

什么是 ZSET?

Redis Sorted Set(有序集合):
- 类似 Set,不允许重复元素
- 每个元素关联一个分数(score)
- 按分数自动排序
- 支持范围查询

示例:
ZADD ranking 100 "article:1"
ZADD ranking 200 "article:2"
ZADD ranking 150 "article:3"

自动排序:
article:2 (200)
article:3 (150)
article:1 (100)

ZSET 特性

特性 1:自动排序
- 按分数从小到大排序
- 分数相同时按字典序
- 支持倒序查询

特性 2:唯一性
- 元素唯一
- 重复添加会更新分数

特性 3:高性能
- O(log N) 添加/删除
- O(log N) 范围查询
- O(1) 获取排名

特性 4:丰富操作
- ZADD:添加/更新
- ZINCRBY:增加分数
- ZRANGE/ZREVRANGE:范围查询
- ZRANK/ZREVRANK:获取排名
- ZCOUNT:统计范围内的元素数量

基础操作

点赞排行榜

实时更新排行榜

时间范围排行榜

24 小时热榜

本周热榜

作者榜

按文章获赞总数

性能优化

优化 1:限制排行榜大小

优化 2:定期清理

优化 3:缓存排行榜结果

课后练习

练习 1

ZSET 的时间复杂度是多少?为什么?

参考答案(3 个标签)
RedisZSET时间复杂度

ZSET 时间复杂度:

ZADD:O(log N)
- 插入/更新元素
- 需要调整排序树

ZINCRBY:O(log N)
- 原子性增加分数
- 需要调整排序树

ZRANGE/ZREVRANGE:O(log N + M)
- log N:找到起始位置
- M:返回 M 个元素

ZRANK/ZREVRANK:O(log N)
- 查找元素排名
- 需要遍历排序树

ZCOUNT:O(log N)
- 统计范围内的元素
- 需要查找范围边界

ZREMRANGEBYRANK:O(log N + M)
- log N:找到删除范围
- M:删除 M 个元素

为什么是 O(log N):

ZSET 底层实现:
- 使用跳跃表(Skip List)
- 或使用字典树(Tree Map)

跳跃表结构:
- 多层索引
- 类似"快速通道"
- 查找时从高层开始

查找过程:
1. 从最高层开始
2. 快速跳过不相关的节点
3. 逐层下降
4. 找到目标元素

时间复杂度:O(log N)

练习 2

如何实现”分页查询”排行榜?

参考答案(3 个标签)
Redis分页ZSET

方案:使用 ZREVRANGE

性能问题:深分页

问题:
- 查询第 1000 页(start=19980, end=19999)
- Redis 需要遍历前 19999 个元素
- 性能差

解决方案:
1. 使用游标分页(基于分数)
2. 限制最大页数(只显示前 100 页)
3. 缓存热门页

练习 3

如何实现”排名变化”功能?

参考答案(3 个标签)
Redis排行榜实时更新

方案:记录排名历史

练习 4

如何实现”段位排行榜”(青铜、白银、黄金)?

参考答案(3 个标签)
排行榜分段游戏化

方案:多个 ZSET

练习 5

如何实现”排行榜实时推送”?

参考答案(3 个标签)
排行榜实时更新WebSocket

方案:WebSocket + Pub/Sub

思考题

  1. 如何处理”分数相同”的情况?

  2. 如何实现”年度榜单”、“月度榜单”?

  3. 如何优化排行榜的”并发更新”性能?

💡 提示:这些问题没有标准答案,建议结合实际情况深入思考。