這是一個常見的面試場景題,考驗的是面試准備范圍的廣度,見過就會答。
思路
基於數據庫
如果之前沒有遇見過,最容易想到的就是平時接觸的最多的數據庫排序。前端每隔一段時間調用接口去查詢數據庫,然后更新排行榜表。
在一個用戶量非常的小的具體場景,這是可行的。
如果是一個游戲排行榜的話,隨着游戲玩家的增加,達到千萬用戶級別的話,雖然可以扯什么查詢慢就加索引,數據量大就分庫分表,但這仍然不是一個特別好的方案。
基於Redis
這個場景其實就是考察 Redis 中 sorted set 數據結構的掌握。
sorted set 是有序集合的意思。
例子:
- key 是 sport:ranking:20210227
- value 是一個集合,且這個集合是有序的
- 集合中的每一個 member 都有一個 score,然后按照這個 score 進行降序排序;
- member 是不可以重復的,但是 score 是可以重復的。
當 member 的 score 一樣的時候,member 按照字典序(lexicographically) 進行排序,所以上圖 jay 在 why 前。
有序集合的操作函數,一共有 32 個。
ZADD 方法
- 添加 member 命令格式:zadd key score member [score member ...]
- 增加 member 的 score 命令格式:zincrby key increment member
- 獲取 member 排名命令格式:zrank/zrevrank key member
- 返回指定排名范圍內的 member 命令格式:zrange/zrevrange key start end [withscores]
1、添加 member
zadd key score member [score member ...]
可以一次添加一對或者多對 score-member
zadd sport:ranking:20210227 10026 why
zadd sport:ranking:20210227 10158 mx 30169 les 48858 skr 66079 jay
執行之后,返回的數字代表添加成功的 member 個數。
2、增加 member 的 score
zincrby key increment member
微信運動排行榜的數據是實時更新的,執行命令:
zincrby sport:ranking:20210227 5000 why
按照 score 倒序:
3、獲取 member 排名
# zrank 按照分數從低到高返回 member 排名
zrank key member
# zrevrank 按照分數從高到低返回 member 排名
zrevrank key member
現在要獲取 jay 的排名,用 zrank 返回結果就是 4,用 zrevrank 時,jay 的排名就是 0:
zrank sport:ranking:20210227 jay
zrevrank sport:ranking:20210227 jay
4、返回指定排名范圍內的 member
member:zrange/zrevrange key start end [withscores]
zrange 是按照 score 從低到高返回指定排名范圍內的 member。
zrevrange 是按照 score 從高到低返回指定排名范圍內的 member。
用 zrevrange 的命令獲取步數排名前三的 member:
zrevrange sport:ranking:20210227 0 2
帶上可選參數 withscores 之后,會返回對應 member 的 score:
要獲取所有用戶的排名:
zrevrange sport:ranking:20210227 0 -1
微信步數排行榜
每個人看見的數據排行數據來源自己的微信好友,而微信好友各不相同,所以看到的排行榜也各不相同。
當前的 key 是 sport:ranking:20210227,里面只包含了某一天的信息,只要在 key 里面加上用戶的屬性就可以了。
例如 key 可以設計為 sport:ranking:why:20210227 ,由於 key 里面多了用戶信息,每個人的 key 都各不相同。
億級用戶排行榜
需要利用分治的思想。
如王者一共 8 個段位,可以有 8 個,這個桶可以是一個 Redis 里面的 8 個不同的 key,甚至是 8 個 Redis 里面各一個 key:
對於億級用戶只分 8 個桶未免太少了,那就根據每個段位里面還有小段位繼續分桶。
還是不夠的話,直接把段位加上各種其他條件換算成積分,然后按照積分來拆分:
當然實際情況下,用戶的落點其實並不是均勻的,這就需要進行數據分析,通過一系列的高數、概率、離散等知識去做個桶大小的預估。