版權聲明:本文為博主原創文章,未經博主允許不得轉載。
1. 需求
Redis 提供了按分數進行排序的有序集合。 比如在游戲里面,比如戰斗力排行,充值排行,用默認的Redis 實現就可以達到需求。
但是,比如等級排行,大家都是30級,誰先到30級誰第一。Redis 默認實現是,相同分數的成員按字典順序排序(0 ~9 , A ~Z,a ~ z),所以相同分數排序就不能根據時間優先來排序。
需要設計一個 【分數 = 等級 + 時間】 ,誰分數大誰第一,最后再根據分數能解析出來等級即可。
2.設計
分數 = 等級 + 時間 (當前系統時間戳)
分數是 64位的長整型 Long (有符號)
1) 設計方式一
long 分數,二進制用高 32位存 等級,低32位存時間(秒精度),那么數據看起是這樣
A 玩家, 10 + 1111111111(時間戳)
后來 B 玩家也到 10 級, 10 + 2222222222(時間戳)
這樣排序,最終還是 B 玩家 會排到第一名,不能達到目的。
2) 設計方式二
long 整數長度總共有 19位,923XXX.......,時間戳 毫秒精度 是 13位,所以只需 14 ~ 19 位存 等級,其他13位存時間。接下來看怎么存。
等級偏移: Math.power(10, 14) = 10000000000000000(14位)
這里有一個最大時間 MAX_TIME = 9999999999999 (13位)
A 玩家,(10 * 等級偏移) + MAX_TIME - 11111111111111( 時間戳),最終分數 10888888888888888
B 玩家,(10 * 等級偏移) + MAX_TIME - 22222222222222( 時間戳),最終分數 10777777777777777
最終排序,A 玩家依然是第一。通過分數可以解析出真實 【等級 = 分數 / 等級偏移,取整】
3. 劣勢
1) 如果有三個,四個排序條件怎么辦,這種情況還是推薦使用數據庫,就別考慮 Redis了 。Redis 優勢在於可以做到實時排行
2) 方式二 14 ~ 19位,那么等級最大數據就只能是 919999,超過這個數就會溢出。可以把時間戳降低到秒級別,可以支持更大數字
4. 總結
以上設計主要還是針對游戲內排行榜,並不能涵蓋所有行業,只能說是借鑒作用,僅供參考。
// 萬仙陣排名變化
public void updateWanxianzhePoints(final String avatarId, final int points) {
jedisTemplate.execute(new JedisCallback() {
@Override
public Object doInJedis(Jedis jedis) {
long updateTime = System.currentTimeMillis();
double timeRank = points + 1 - updateTime / Math.pow(10, (int) Math.log10(updateTime) + 1);
jedis.zadd(FsGameDbConstants.KEY_LIST_WANXIANZHEN_POINTS, timeRank, avatarId);
LoggerHelper.infoParams("updateWanxianzhePoints avatarId=", avatarId, " points=", points);
return null;
}
});
}
取出來轉化成整型
int points = Double.valueOf(rr.getScore()).intValue();