用 Redis 實作 Leaderboard(排行榜)
Sorted set (ZSET)
用 Redis 做排行榜是常見又有效率的做法,尤其在你需要快速讀寫與排名的時候。Redis 剛好內建一個非常適合的資料結構:Sorted Set(ZSET)。
🧠 Redis Sorted Set 入門
Redis 的 Sorted Set 是一組不重複的字串(例如 user ID 或帳號名稱),每一個都配上一個浮點數的分數(score)。整個集合會自動依分數排序。
對排行榜來說:
- 玩家 / 使用者 ID 就是 member。
- **分數(例如積分、擊殺數、評分)**就是 sorted set 裡的 score。
✅ Redis 排行榜的基本操作
1. 新增或更新玩家分數
bash
ZADD leaderboard <score> <user_id>
✅ 使用者不存在就新增,已經在集合裡就更新分數。
範例:
bash
ZADD leaderboard 1500 "user:123"
ZADD leaderboard 1800 "user:456"
2. 取前 N 名
bash
ZREVRANGE leaderboard 0 N-1 WITHSCORES
- 用
ZREVRANGE取由高到低(分數最高的在前)。 WITHSCORES會連分數一起回傳。
範例:
bash
ZREVRANGE leaderboard 0 9 WITHSCORES # Top 10 players
3. 取某位玩家的排名
bash
ZREVRANK leaderboard <user_id>
- 回傳該玩家在遞減排序下的排名,從 0 開始。
範例:
bash
ZREVRANK leaderboard "user:123" # e.g., returns 5
4. 取某位玩家的分數
bash
ZSCORE leaderboard <user_id>
範例:
bash
ZSCORE leaderboard "user:123" # e.g., returns 1500.0
5. 移除玩家
bash
ZREM leaderboard <user_id>
範例:
bash
ZREM leaderboard "user:123"
🧱 可以再加的東西
🕐 依時間切分的排行榜
週榜、月榜的做法:
-
每個時間區間用各自的 key:
leaderboard:weekly:2025-W20leaderboard:monthly:2025-05
-
用排程工作歸檔或刪掉舊的排行榜。
🧾 附帶資料(metadata)
Redis Sorted Set 沒辦法直接存額外資料(例如暱稱、頭像)。做法:
-
sorted set 裡只放 user ID。
-
使用者的其他資料放在 Redis hash 或另一個資料庫:
bashHGETALL user:123 # e.g., {"username": "Alice", "avatar": "..."}
🔁 分數累加
bash
ZINCRBY leaderboard 100 "user:123"
把 user:123 現有的分數加 100。
🧪 範例情境(遊戲)
bash
ZADD game:leaderboard 2000 "player:alice"
ZADD game:leaderboard 1900 "player:bob"
ZREVRANGE game:leaderboard 0 4 WITHSCORES # top 5
ZREVRANK game:leaderboard "player:alice" # alice's rank
🧩 可擴展性的幾點注意
- Redis 是記憶體內的:非常快,但沒開持久化(RDB/AOF)資料就是易失的。
- 使用者量非常大時,考慮把排行榜分片(sharding),或改用 Redis Cluster。
- 如果精確度不是那麼關鍵,可以批次更新,或做近似排行榜(例如定期同步回資料庫)。