面試場景題:如何設計一個排行榜?


這是一個常見的面試場景題,考驗的是面試准備范圍的廣度,見過就會答。

思路

基於數據庫

如果之前沒有遇見過,最容易想到的就是平時接觸的最多的數據庫排序。前端每隔一段時間調用接口去查詢數據庫,然后更新排行榜表。

在一個用戶量非常的小的具體場景,這是可行的。

如果是一個游戲排行榜的話,隨着游戲玩家的增加,達到千萬用戶級別的話,雖然可以扯什么查詢慢就加索引,數據量大就分庫分表,但這仍然不是一個特別好的方案。

基於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 個桶未免太少了,那就根據每個段位里面還有小段位繼續分桶。

還是不夠的話,直接把段位加上各種其他條件換算成積分,然后按照積分來拆分:

當然實際情況下,用戶的落點其實並不是均勻的,這就需要進行數據分析,通過一系列的高數、概率、離散等知識去做個桶大小的預估。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM