我們正在構建一個巨大的多玩家教育遊戲,在領導板(根據聚集的XPs獲得)的數百萬條目。遊戲結束後,我們需要顯示排行榜以及該玩家/學生的排名。 但是這個排行榜有一些過濾器(全球/按國家,按月份/年份/今天,按年齡等),可以混合在一起,例如'給我排行榜for my Country
for the last month
'。組合數是〜20。巨大的排行榜排名與過濾
我的問題是如何存儲這樣一個定期更新的結構;重新計算排名必須在每場比賽後進行。目前,一個典型的完整排行榜對來自150多個國家的玩家來說有500萬的參賽作品。
我曾經有MySQL簇表(用戶ID,XPS,countryid)與3個節點,但排序由(這需要從DB的所有數據或者在DBMS或應用程序)被證明XPS是爲數字太慢變得更大(> 20K的用戶)。這是一個有趣的post,但對於每個查詢而言,又是半秒太多。
然後我們使用REDIS(見post),但過濾是這裏的問題。我們使用單獨的名單TOP 5和其他。 TOP 5立即更新,其餘時間延遲20-30分鐘。實際上,我們根據排行榜的一個緩存實例對這個用戶進行了排名(儘管使用了真正的XPs,而不是緩存),所以這是可以接受的。非Top5的實時並不是先決條件。 這對一個全球排名很合適,但是如何根據月份和/或國家和/或年齡過濾結果。我們是否需要爲每個過濾組合列出清單?我們還測試了Java中的自定義結構(使用它作爲與REDIS功能類似的Java緩存服務器),但仍在嘗試使用它。哪個是結構的最佳組合來實現我們的目標?我們最終使用每個過濾組合的一個列表,例如
Map<FilteringCombination, SortedList<User>>
,然後執行二進制搜索到特定鍵的列表。通過這種方式,完成的遊戲需要插入一些X,但它需要X * NumOfPlayers空間,這比保存單個列表多了X倍(不確定這是否適合內存,但我們總是可以在這裏創建一個集羣將組合分割到不同的服務器)。這裏有一個關於如何在發生故障時重建緩存的問題,但這是我們可以處理的另一個問題。擴展上述方法,如果我們在每個列表中定義評分桶(例如0-100xp的桶,101-1000xp的另一個桶,1001-10000xp的另一個等等),我們可能會略微提高性能。分組策略將基於玩家在我們遊戲中的xp分佈。確實,這種分佈在現實世界中是動態的,但我們已經看到,在幾個月後的變化是微不足道的,考慮到XP總是在增加,但新用戶也會來。
我們還利用集羣鍵和白行功能測試Cassandra的自然排序,儘管我們知道有幾百萬行可能不容易處理。
總之,這就是我們需要實現的。如果用戶(讓我們命名她的用戶X)不包含在TOP5名單,我們需要顯示該用戶的一些周圍的玩家一起排名(以上如2和表2)如下面的例子:
Global TOP 5 My Global Ranking (425) My Country Ranking Other Rankings
1. karen (12000xp) 423. george 1. david
2. greg (11280xp) 424. nancy 2. donald
3. philips (10293xp) **425. UserX** 3. susan
4. jason (9800xp) 426. rebecca **4. UserX**
5. barbara (8000xp) 427. james 5. teresa
我已經研究了許多SO或其他帖子,但仍無法找到有效更新和過濾大型Leaderboard表的解決方案。您會選擇哪一種候選解決方案,以及可能的性能改進(空間+內存+(插入/搜索CPU成本))?
謝謝你的回答。我會嘗試一下您的建議並上傳任何有趣的結果。關於VS的寫法,請記住,它們很可能大部分是平等的。假設有20名玩家的遊戲,當遊戲結束時,所有用戶都可以看到當前的排行榜。因此,每個用戶a)更新她的XP,但她也b)查看更新的排名。有一些瀏覽也只是在排名上看,但瀏覽排名表並不像玩遊戲那麼普遍,因此閱讀結果往往比寫作更經常。 –
......目前,每天約有100萬場比賽〜每秒11場比賽。另外,由於每個線程已經有很多的排序請求(線程在池中),我不確定使用多線程排序會大大提高性能,但我也會測試它。 –
爲什麼你需要在你建議的代碼中使用xpIndex Map? –