Redis Sorted Set构建实时排行榜
来源:17golang原创
时间:2026-11-15 11:28:07 239浏览 收藏
Redis Sorted Set 很适合做实时排行榜:把用户或选手作为 member,把积分、销量或热度作为 score,所有成员放进同一个 key。分数变化时直接更新,读取时按名次取出 Top N,不需要在应用层把整张榜单重新排序。
官方地址:https://redis.io/docs/latest/develop/
最小可用方案是:用ZADD leaderboard:season-1 score member写入分数,用ZRANGE leaderboard:season-1 0 9 REV WITHSCORES读取前十名,再用ZRANK和ZSCORE查询个人名次与分数。注意名次从 0 开始,同分成员按字典序排列。
先把排行榜建模成 Sorted Set
Sorted Set 的成员唯一,但每个成员都绑定一个浮点数分数。排行榜 key 可以按赛季、活动或业务周期隔离,例如 leaderboard:season-1。同一 member 再次写入时不是新增第二行,而是更新原来的 score。

初始化数据可以直接使用 Redis CLI。下面的示例是命令写法,注释放在代码块外,避免把 CLI 输出误当成注释:
# 写入三名选手;相同 member 再执行会更新分数
ZADD leaderboard:season-1 128 alice
ZADD leaderboard:season-1 256 bob
ZADD leaderboard:season-1 192 carol
# 给 alice 加分时覆盖旧分数,最终分数变成 148
ZADD leaderboard:season-1 148 alice
如果业务中的分数是增量,例如每答对一题加 10 分,可使用 ZINCRBY。不要在应用层先读取旧分数再计算,否则并发更新时容易产生覆盖。
# 原子增加 alice 的分数;不存在的成员会从 0 开始
ZINCRBY leaderboard:season-1 10 alice
用 ZRANGE 读取 Top N
Redis 6.2 以后,推荐用 ZRANGE 组合 REV、LIMIT 和 WITHSCORES 完成倒序榜单查询。0 是第一条,结束位置包含在结果中,所以前十名是 0 9:
# 按 score 从高到低取前 10 名,并同时返回分数
ZRANGE leaderboard:season-1 0 9 REV WITHSCORES
如果要做分页,使用固定的偏移量和数量即可:
# 取第 11 到第 20 名;offset 是 10,count 是 10
ZRANGE leaderboard:season-1 0 -1 REV LIMIT 10 10 WITHSCORES
这类查询的复杂度是 O(log(N)+M),其中 N 是集合成员数,M 是返回数量。排行榜接口不要一次返回几十万条,页面只需要 Top N 时就把范围限制在需要的窗口。
查询个人名次与分数
榜单页面通常还要显示“我排第几”。倒序排行榜里,直接使用 ZREVRANK;如果你的客户端只暴露了统一的 ZRANK 选项,也要明确使用倒序参数,避免把低分第一名误当成高分第一名。
# 查询 alice 在高分到低分榜单中的 0-based 名次
ZREVRANK leaderboard:season-1 alice
# 查询 alice 的当前分数
ZSCORE leaderboard:season-1 alice
返回名次后,展示层一般加 1 转成人类习惯的名次;不要直接把 Redis 的 0-based 值显示为“第 0 名”。成员不存在时,排名和分数都是空结果,接口应按“暂无排名”处理,而不是把空值转换成 0。

同分、清理和接口边界
Sorted Set 中 member 唯一;当多个成员的 score 相同时,Redis 会按 member 的字典序排列。因此如果产品要求“同分按到达时间排序”,不能只把业务分数原样写入,需要把时间或序号编码进可比较的 score,或者额外维护一个可解释的并列规则。编码时要注意浮点精度,不要把过大的整数直接当作可精确比较的浮点数。
如果排行榜只保留前 10000 名,可以在写入后删除尾部成员。删除命令的结束位置同样是包含关系:
# 保留 rank 0 到 9999,删除从第 10000 名开始的成员
ZREMRANGEBYRANK leaderboard:season-1 10000 -1
生产接口建议把榜单 key 与赛季、租户或活动 ID 组合,避免不同业务共用 key;把读取范围限制在接口需要的窗口;对空榜单和不存在 member 返回明确的业务状态。需要按分数区间筛选时,优先使用 ZRANGE ... BYSCORE,不要先读取全部成员再由应用过滤。
常见问题
为什么排行榜名次从 0 开始?
Redis 返回的是从 0 开始的 rank,这是数组式索引。展示给用户时使用 rank + 1,但分页计算仍按 0-based 范围处理。
同一个用户可以在一个 Sorted Set 里出现两次吗?
不可以。member 是唯一的;再次 ZADD 会更新该 member 的 score。如果需要保留同一用户的多次成绩,应把“用户 ID + 记录 ID”组成不同 member,并另存用户维度的最新成绩。
小结:Sorted Set 负责按 score 维护有序成员,ZADD/ZINCRBY 负责写入,ZRANGE ... REV LIMIT 负责 Top N,ZREVRANK/ZSCORE 负责个人信息。把同分规则、空结果和榜单上限提前定义好,实时排行榜就能保持简单可控。
-
311 收藏
-
483 收藏
-
379 收藏
-
172 收藏
-
464 收藏
-
331 收藏
-
421 收藏
-
184 收藏
-
209 收藏
-
406 收藏
-
135 收藏
-
401 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习