ZSet 排行榜是什么
排行榜的本质是「按分数排序并支持按名次取数」,这正是 ZSet 的能力:成员唯一、分数可重复,内部按分数排序存储,因此取前 N 名、查某人名次、取某人分数都是高效操作。ZREVRANGE 从高到低取区间,ZREVRANK 返回从高到低的排名,ZSCORE 取单一成员的分数。同分时 ZSet 按成员字典序排列,这个默认规则往往与业务期望的「先到先得」不一致。
基本信息
| 写入 | ZADD board <score> <member>,分数可整数也可浮点 |
|---|---|
| 取榜 | ZREVRANGE board 0 9 WITHSCORES 取前 10 名 |
| 查名次 | ZREVRANK board member,从 0 开始,越大越靠后 |
| 查分数 | ZSCORE board member,成员不存在返回 nil |
| 复杂度 | ZADD 与查询为 O(log N),区间取数为 O(log N + M) |
典型使用场景
- 积分榜、销售额榜、点赞榜等按数值排序的实时榜单,写入后立即可见
- 个人维度查询:查我的名次与前后几名,用 ZREVRANK 加 ZREVRANGE 组合完成
- 分段榜单:按日、周、月各建一个 ZSet,定时合并或分别展示,避免大 key
- 带时间维度的排行:把时间戳编进分数小数位,实现同分按提交时间先后排序
- 榜单数据源同步:离线算好的榜单一次性 ZADD 导入,在线读路径只做取数
常用示例
常用示例
redis-cli ZADD board 1200 u1 980 u2 1500 u3
redis-cli ZREVRANGE board 0 9 WITHSCORES # 前 10 名与分数
redis-cli ZREVRANK board u2 # u2 的名次,从 0 开始
redis-cli ZSCORE board u1 # 单个成员分数
redis-cli ZINCRBY board 50 u2 # 原子加 50 分
redis-cli ZREVRANGE board 0 9 # 只要成员,不要分数
redis-cli ZCARD board # 参与排名的总人数排序规则与分数设计
| 需求 | 分数设计 | 说明 |
|---|---|---|
| 按分数降序 | 直接存分数 | ZREVRANGE 取前 N |
| 同分按时间先到先排 | 分数整数部分放分值,小数部分放反向时间戳 | 越早提交小数越大,排越前 |
| 同分按名称排序 | 不加处理 | 默认按成员字典序,中文与数字需确认编码顺序 |
| 只保留前 N 名 | ZADD 后用 ZREMRANGEBYRANK 裁剪 | 控制榜单长度,避免无限增长 |
复合分数的写法与精度:双精度浮点约 15 到 16 位有效数字,常见做法是分值乘以较大系数后加时间戳的反向小数部分。分值本身超过千万级时小数位会被挤掉,需要先评估量级再决定是否使用复合分数。
分页的一致性:ZREVRANGE 按索引分页在数据持续变动时会出现重复或漏项,例如取第 11 到 20 名期间有人插入前排,原本的第 11 名会被挤到第 12。运营展示类页面可以接受,涉及发放奖励的结算页应改为按分数区间取或先固化快照。