Redis 有序集合 Sorted Set

ZSet 在 Set「成员唯一」的基础上给每个成员挂一个分数(score),集合按分数升序排列,可随时按排名区间取值。排行榜、限时活动积分榜都靠它,是面试与实战的高频类型。

添加成员

ZADD 带分数添加成员,成员已存在则只更新分数,返回新增个数:

ZADD leaderboard 100 user1 90 user2 88 user3
# 输出:(integer) 3
ZADD leaderboard 95 user2     # user2 分数更新为 95
# 输出:(integer) 0

分数可以是整数或小数(如 9.5),同一集合内分数允许并列。

按排名取成员

ZRANGE 按分数升序取区间,配 REV 变降序,WITHSCORES 带分数:

ZRANGE leaderboard 0 -1
# 输出:1) "user3" 2) "user2" 3) "user1"
ZRANGE leaderboard 0 -1 WITHSCORES
# 输出:1) "user3" 2) "88" 3) "user2" 4) "95" 5) "user1" 6) "100"
ZRANGE leaderboard 0 1 REV WITHSCORES   # 降序取前两名
# 输出:1) "user1" 2) "100" 3) "user2" 4) "95"

排行榜「取 Top10」就是 ZRANGE key 0 9 REV WITHSCORES 一条命令的事。

查询分数与排名

ZSCORE 看分数,ZRANK 看升序名次(从 0 开始):

ZSCORE leaderboard user1
# 输出:"100"
ZRANK leaderboard user1
# 输出:(integer) 2          # 升序第 3 名
ZRANK leaderboard user3
# 输出:(integer) 0

降序名次可用 ZRANGE ... REV 换算,或直接看集合大小推算。

更新与删除

ZINCRBY 给分数加增量(写积分流水最常用),ZREM 删除成员:

ZINCRBY leaderboard 10 user1
# 输出:"110"                  # 完成一单任务加 10 分
ZREM leaderboard user3
# 输出:(integer) 1
ZCARD leaderboard
# 输出:(integer) 2            # 成员总数

ZINCRBY 是原子操作,多人并发加分不会丢更新。

常用命令一览

命令作用
ZADD添加 / 更新成员分数
ZRANGE按名次区间取值,REV 降序
ZSCORE / ZRANK查分数 / 查名次
ZINCRBY分数原子增减
ZREM删除成员
ZCARD成员总数
ZCOUNT分数在区间内的成员数
ZREMRANGEBYSCORE按分数区间批量删除

典型场景

积分排行榜:每次用户得分 ZINCRBY 更新,展示时降序取前 N:

ZINCRBY game:rank 5 player_88
ZINCRBY game:rank 8 player_12
ZRANGE game:rank 0 9 REV WITHSCORES

延迟/定时任务:把执行时间戳当分数,轮询取「已到期」任务即可(到期后成员删除或另存状态)。

易踩坑

  • 分数并列时按成员名做字典序排序,两个并列第 1 实际还有个先后;
  • 元素很少时 ZSet 用紧凑编码存储,量大后自动转跳表,无需手动干预;
  • 排行榜要「先到先得」,可用 时间戳修正分数(如 分数 = 业务分×大数 - 秒级时间戳)避免并列抖动,量级设计要防溢出。

小结

ZSet 的价值 = Set 唯一性 + 可排序分数。ZADD/ZINCRBY 维护分数,ZRANGE ... REV WITHSCORES 出排行榜,ZSCORE/ZRANK 支持名次查询。记住分数并列的字典序规则,排行榜功能就稳了。

笔记加载中…