前言:
最近想實現一個網頁闖關游戲的排行榜設計, 相對而言需求比較簡單. 秉承前廠長的訓導: “做一件事之前, 先看看別人是怎么做的”. 於是乎網上搜索並參考了不少排行榜的實現機制, 很多人都推薦了redis的有序集(sorted set). 我覺得十分的贊, 技術方案很難在超越已有的模型了, 就看業務上的需求, 做些小改動.
相關文章系列:
記得大概在一年前吧, 寫過兩篇關於排行榜的文章, 不過那是針對游戲平台(類似微信, 手Q等)而言的. 每個用戶都有自己的排行榜, 不是全局性的.
• 社交游戲的排行榜設計和實現(1)
• 社交游戲的排行榜設計和實現(2)
有序集初體驗:
先來看幾個后續會使用的redis命令語法:
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源碼的定義如下:
typedef struct zset { // 字典 dict *dict; // 跳躍表 zskiplist *zsl; } zset;
這樣就比較清晰了, 它采用了復合結構, 字典維護了name=>score的映射表, 而跳躍表則維護了按score排序的列表. 按name和按score的范圍查詢都天然支持.
具體的解讀,可參考<<redis 設計和實現--有序集>>.同時引用官文文檔的一張示意圖:
總結:
其實我很早就想這篇文章,作為一個游戲編程的愛好者而言,排行榜作為一個基礎服務,必然會接觸到.早做准備必然是好事,后續如果有機會.我想依據實際的項目,來具體闡述一下,畢竟理論和實戰, 還是有所差異.
公眾號&游戲站點:
個人微信公眾號: 木目的H5游戲世界
個人游戲作品集站點, www.mmxfgame.com, 請點擊訪問: http://120.26.221.54/.