Redis ZSet(有序集合)
→ 返回 Redis
ZSet(Sorted Set) 为每个 member 关联一个 score(双精度浮点),按 score 排序。member 唯一,同一 member 重复 ZADD 会更新 score。是 排行榜、延迟队列、滑动窗口限流 的首选结构。
完整命令表见 基础命令 · ZSet。
ZADD rank:daily 9500 user:1001 8800 user:1002
ZINCRBY rank:daily 200 user:1001
ZREVRANGE rank:daily 0 9 WITHSCORES # Top 10
ZREVRANK rank:daily user:1001底层结构
- 每个 ZSet:跳表(skiplist) + 哈希表(member → score),保证 O(log N) 范围查询与 O(1) 查分。
- member 较长或元素极多时注意内存;单 key 元素过多会成为热 key。
典型场景
排行榜
| Key 设计 | member | score |
|---|---|---|
rank:game:20240601 | userId | 积分/步数 |
rank:friend:{uid}:20240601 | friendId | 好友榜 |
更新:ZINCRBY 或 ZADD(覆盖为最新值)。
完整方案:排行榜与实时计数、点赞计数。
延迟队列
score = 执行时间戳(毫秒),定时任务 ZRANGEBYSCORE delay 0 now LIMIT n 取出到期 member 再 ZREM。
ZADD delay:queue 1718000000000 job:1001
ZRANGEBYSCORE delay:queue 0 1718000100000 LIMIT 0 10滑动窗口限流
score = 请求时间戳,member = 唯一请求 id;窗口内 ZCOUNT 或先 ZREMRANGEBYSCORE 删过期再计数。
热搜 / 权重时间线
score 可编码「热度 + 时间衰减」;注意与 热搜 的缓存层级配合。
设计注意
| 问题 | 处理 |
|---|---|
| 分数相同 | 按 member 字典序 二级排序,非插入顺序 |
| 并列排名 | 业务若要「并列第 1」需自行处理 rank 显示 |
| 热 key | 大榜拆分为 rank:shard:0… 或只缓存 Top N |
| 持久化 | 大 ZSet RDB/AOF 重写成本高,控制单 key 规模 |
| 与 Set 区别 | Set 无 score;去重用 Set,排序用 ZSet |
ZSet vs Hash
| 需求 | 选型 |
|---|---|
| 只要对象字段 | Hash |
| 要排序、TopN、按分数范围 | ZSet |
集群
- 一个 ZSet 一个 key → 单 slot;不支持跨 key 的 ZSet 分片(除非业务拆 key)。
ZUNIONSTORE多 key 时要求 same slot(可用 hash tag:rank:{uid}:daily)。
Spring Boot
redisTemplate.opsForZSet().add("rank:score", "player1", 9500);
redisTemplate.opsForZSet().incrementScore("rank:score", "player1", 200);
Set<ZSetOperations.TypedTuple<Object>> top10 =
redisTemplate.opsForZSet().reverseRangeWithScores("rank:score", 0, 9);
Long rank = redisTemplate.opsForZSet().reverseRank("rank:score", "player1");详见 Redis 集成。