1. 程式人生 > >基於redis的排行榜設計和實現

基於redis的排行榜設計和實現

http://www.cnblogs.com/mumuxinfei/p/5013357.html

前言:
  最近想實現一個網頁闖關遊戲的排行榜設計, 相對而言需求比較簡單. 秉承前廠長的訓導: “做一件事之前, 先看看別人是怎麼做的”. 於是乎網上搜索並參考了不少排行榜的實現機制, 很多人都推薦了redis的有序集(sorted set). 我覺得十分的贊, 技術方案很難在超越已有的模型了, 就看業務上的需求, 做些小改動. 

相關文章系列:
  記得大概在一年前吧, 寫過兩篇關於排行榜的文章, 不過那是針對遊戲平臺(類似微信, 手Q等)而言的. 每個使用者都有自己的排行榜, 不是全域性性的.
  • 

社交遊戲的排行榜設計和實現(1)
  • 社交遊戲的排行榜設計和實現(2) 

有序集初體驗:
  先來看幾個後續會使用的redis命令語法:

1

2

3

4

5

6

7

8

9

10

11

ZADD key score1 member1 [score2 member2]

新增一個或多個成員到有序集合,或者如果它已經存在更新其分數

 

ZRANGE key start stop [WITHSCORES]

由索引返回一個成員範圍的有序集合。

 

ZSCORE key member

獲取給定成員相關聯的分數在一個有序集合

 

ZRANK key member

確定成員的索引中有序集合

  更詳細和完整的命令, 請點選該連結
  • 案例設計
  輸入5個學生的成績(name, score), 實現top-3的查詢, 修改某個同學的得分, 再次查詢top-3.
  1). 新增成績記錄
  新增 (lucy, 61), (lily 60), (uncle wang, 10), (lilei, 98), (hanmeimei, 99) 這5人的成績, 並假定class_rank 為sorted set的name.
  
  2). 第一次top-3查詢
  
  3). 更新uncle wang的分數
  


  注: zadd命令既可以新增, 也可以更新
  4). 再次top-3查詢
  
  場景的設計, 以及最後輸出的結果與預期符合.看來redis的sorted set滿足需求, 而且特別的方便.

原理淺析:
  有了前文的直觀體驗, 再來研究redis中的有序集合(sorted set), 究竟是何種資料結構, 它能提供什麼樣的介面, 以及滿足什麼樣的需求呢?
  我們來探究下它支援的功能, 首先當然就是支援按分值排序的功能. 由此可以猜測它底層是按score為key, name為value的tree結構(因為支援範圍查詢, 以及按分值排序). 但是該有序集又支援按name來修改score. 這樣需求下, 又演變成name為key, score為value的map結構了. 單獨的一種資料結構, 無法滿足其需求, 兩個都不可或缺. 那答案究竟是什麼?
  redis原始碼的定義如下:

1

2

3

4

5

6

typedef struct zset {

    // 字典

    dict *dict;

    // 跳躍表

    zskiplist *zsl;

} zset;

  這樣就比較清晰了, 它採用了複合結構, 字典維護了name=>score的對映表, 而跳躍表則維護了按score排序的列表. 按name和按score的範圍查詢都天然支援.
  具體的解讀,可參考<<redis 設計和實現--有序集>>.同時引用官文文件的一張示意圖:
  

總結:
  其實我很早就想這篇文章,作為一個遊戲程式設計的愛好者而言,排行榜作為一個基礎服務,必然會接觸到.早做準備必然是好事,後續如果有機會.我想依據實際的專案,來具體闡述一下,畢竟理論和實戰, 還是有所差異.