ZADD + ZRANGE 是游戏排行榜最稳组合,因ZSet天然支持按分数排序、去重、动态更新,且ZADD覆盖写入分数、ZRANGE覆盖拉取Top N;需注意ZADD参数(XX/NX/默认行为)、分数格式、key命名规范,ZRANGE必须加WITHSCORES和DESC,相同分数时按member字典序排列。

为什么 ZADD + ZRANGE 是游戏排行榜最稳的组合
因为 ZSet 天然支持按分数排序、去重、动态更新,而 ZADD 和 ZRANGE 刚好覆盖「写入玩家分数」和「拉取 Top N 排名」这两个核心动作。其他命令比如 ZINCRBY 虽然也能更新,但无法原子性处理「首次插入+设初值」;ZREVRANGE 看似顺手,但默认是降序——游戏排行榜要的是“分数高排前面”,得显式加 WITHSCORES 和 DESC 才不翻车。
ZADD 写入时必须注意的三个参数细节
常见错误是只传 ZADD leaderboard 1000 player:123,结果发现同个玩家多次插入导致重复记录,或者分数没更新成功。
-
ZADD默认是「仅新增」模式,要更新已有成员分数,必须加XX(只更新)或NX(只新增),更常用的是不加任何选项——它会自动更新已存在成员的 score - 分数必须是能转成浮点数的字符串,
"inf"或"-inf"合法,但"1e5"在某些客户端里可能被误解析,建议统一用整数字符串如"100000" - key 名别带空格或特殊符号,
leaderboard:week:202406没问题,leaderboard:2024-06在部分运维脚本里容易被当参数分割,优先用冒号或下划线
ZRANGE 拉榜单时容易漏掉的关键修饰符
直接 ZRANGE leaderboard 0 9 只返回用户 ID,根本不知道谁第几、分数多少——这在调试期看不出问题,上线后运营查数据就抓瞎。
- 必须加
WITHSCORES,否则拿不到分数:ZRANGE leaderboard 0 9 WITHSCORES - 默认升序(score 小的在前),游戏排行榜需要降序,得加
DESC:ZRANGE leaderboard 0 9 WITHSCORES DESC - 如果只要前 10 名但不确定有没有满 10 人,用
0 -1不安全,应明确范围;想跳过前 3 名取第 4–13 名,写成3 12,不是4 13(索引从 0 开始)
真实场景中 ZSet 的边界问题:分数相同怎么办
分数相同时,Redis 按 member 字典序排——player:999 会排在 player:1000 前面,哪怕数字上 999
- 解决办法不是拼接时间戳(太重),而是把分数设计成「主分 × 1000000 + 子序号」,比如
1000 * 1000000 + 123456,保证全局唯一且可读 - 如果业务允许并列,就接受字典序,但要在前端展示时加「并列第 X 名」提示,不能只显示「第 5 名」误导用户
-
ZRANK和ZREVRANK返回的是索引位置,分数相同时它们返回的 rank 不同——ZRANK返回升序位置,ZREVRANK返回降序位置,查排名时务必用对命令
分数精度、member 唯一性、rank 计算逻辑这三块,随便一个没对齐,排行榜就会出现“玩家A明明分更高却排在B后面”这种线上事故。真出问题时,先用 ZRANGE key 0 -1 WITHSCORES 看原始数据,别急着改代码。


















