一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - 利用Redis的有序集合實現排行榜功能實例代碼

利用Redis的有序集合實現排行榜功能實例代碼

2019-11-22 19:30justudy Redis

這篇文章主要給大家介紹了關于如何利用Redis的有序集合實現排行榜功能的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

前言

游戲中存在各種各樣的排行榜,比如玩家的等級排名、分數排名等。玩家在排行榜中的名次是其實力的象征,位于榜單前列的玩家在虛擬世界中擁有無尚榮耀,所以名次也就成了核心玩家的追求目標。

一個典型的游戲排行榜包括以下常見功能:

  1. 能夠記錄每個玩家的分數;
  2. 能夠對玩家的分數進行更新;
  3. 能夠查詢每個玩家的分數和名次;
  4. 能夠按名次查詢排名前N名的玩家;
  5. 能夠查詢排在指定玩家前后M名的玩家。

更進一步,上面的操作都需要在短時間內實時完成,這樣才能最大程度發揮排行榜的效用。

由于一個玩家名次上升x位將會引起x+1位玩家的名次發生變化(包括該玩家),如果采用傳統數據庫(比如MySQL)來實現排行榜,當玩家人數較多時,將會導致對數據庫的頻繁修改,性能得不到滿足,所以我們只能另想它法。

Redis作為NoSQL中的一員,近年來得到廣泛應用。與Memcached相比,Redis擁有更多的數據類型和操作接口,具有更大的適用范圍,其中的有序集合(sorted set,也稱為zset)就非常適合于排行榜的構建。下面簡要總結一下。

1. Redis的安裝

Ubuntu下安裝Redis非常簡單,執行如下命令即可:

?
1
$ sudo apt-get install redis-server

安裝完畢,運行命令行客戶端redis-cli就可以訪問本地redis服務器。

?
1
2
$ redis-cli
redis 127.0.0.1:6379>

如果要使用最新版本,需要到Redis官網(redis.io)下載最新的代碼自行編譯,步驟略。

2. ZSet的常用命令

有序集合首先是集合,其成員(member)具有唯一性,其次,每個成員關聯了一個分數(score),使得成員可以按照分數排序。關于有序集合的介紹見redis.io/topics/data…,其命令見redis.io/commands#so…。

下面介紹幾個能用于排行榜的命令。

假設lb為排行榜名稱,user1、user2等為玩家唯一標識。

1) zadd——設置玩家分數

命令格式:zadd 排行榜名稱 分數 玩家標識 時間復雜度:O(log(N))

下面設置了4個玩家的分數,如果玩家分數已經存在,則會覆蓋之前的分數。

?
1
2
3
4
5
6
7
8
redis 127.0.0.1:6379> zadd lb 89 user1
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user2
(integer) 1
redis 127.0.0.1:6379> zadd lb 95 user3
(integer) 1
redis 127.0.0.1:6379> zadd lb 90 user4
(integer) 1

2) zscore——查看玩家分數

命令格式:zscore 排行榜名稱 玩家標識 時間復雜度:O(1)
下面是查看user2這個玩家在lb排行榜中的分數。

?
1
2
redis 127.0.0.1:6379> zscore lb user2
95

3) zrevrange——按名次查看排行榜

命令格式:zrevrange 排行榜名稱 起始位置 結束位置 [withscores] 時間復雜度:O(log(N)+M)

由于排行榜一般是按照分數由高到低排序的,所以我們使用zrevrange,而命令zrange是按照分數由低到高排序。

起始位置和結束位置都是以0開始的索引,且都包含在內。如果結束位置為-1則查看范圍為整個排行榜。

帶上withscores則會返回玩家分數。

下面為查看所有玩家分數。

?
1
2
3
4
5
6
7
8
9
10
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user3”
“95”
“user2”
“95”
“user4”
“90”
“user1”
“89”

下面為查詢前三名玩家分數。

?
1
2
3
4
5
6
7
8
redis 127.0.0.1:6379> zrevrange lb 0 2 withscores
 
“user3”
“95”
“user2”
“95”
“user4”
“90”

4) zrevrank——查看玩家的排名

命令格式:zrevrank 排行榜名稱 玩家標識 時間復雜度:O(log(N))

與zrevrange類似,zrevrank是以分數由高到低的排序返回玩家排名(實際返回的是以0開始的索引),對應的zrank則是以分數由低到高的排序返回排名。

下面是查詢玩家user3和user4的排名。

?
1
2
3
4
redis 127.0.0.1:6379> zrevrank lb user3
(integer) 0
redis 127.0.0.1:6379> zrevrank lb user1
(integer) 3

5) zincrby——增減玩家分數

命令格式:zincrby 排行榜名稱 分數增量 玩家標識 時間復雜度:O(log(N))

有的排行榜是在變更時重新設置玩家的分數,而還有的排行榜則是以增量方式修改玩家分數,增量可正可負。如果執行zincrby時玩家尚不在排行榜中,則認為其原始分數為0,相當于執行zdd。

下面將user4的分數增加6,使其名次上升到第一位。

?
1
2
3
4
5
6
7
8
9
10
11
12
redis 127.0.0.1:6379> zincrby lb 6 user4
“96”
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user4”
“96”
“user3”
“95”
“user2”
“95”
“user1”
“89”

6) zrem——移除某個玩家

命令格式:zrem 排行榜名稱 玩家標識 時間復雜度:O(log(N))

下面移除玩家user4。

?
1
2
3
4
5
6
7
8
9
10
redis 127.0.0.1:6379> zrem lb user4
(integer) 1
redis 127.0.0.1:6379> zrevrange lb 0 -1 withscores
 
“user3”
“95”
“user2”
“95”
“user1”
“89”

7) del——刪除排行榜

命令格式:del 排行榜名稱

排行榜對象在我們首次調用zadd或zincrby時被創建,當我們要刪除它時,調用redis通用的命令del即可。

?
1
2
3
4
redis 127.0.0.1:6379> del lb
(integer) 1
redis 127.0.0.1:6379> get lb
(nil)

3. 相同分數問題

免費的方案總有那么一些不完美。從前面的例子我們可以看到,user2和user3具有相同的分數,但在按分數逆序排序時,user3排在了user2前面。而在實際應用場景中,我們更希望看到user2排在user3前面,因為user2比user3先加入排行榜,也就是說user2先到達該分數。

但Redis在遇到分數相同時是按照集合成員自身的字典順序來排序,這里即是按照”user2″和”user3″這兩個字符串進行排序,以逆序排序的話user3自然排到了前面。

要解決這個問題,我們可以考慮在分數中加入時間戳,計算公式為:

帶時間戳的分數 = 實際分數*10000000000 + (9999999999 – timestamp)

timestamp我們采用系統提供的time()函數,也就是1970年1月1日以來的秒數,我們采用32位的時間戳(這能堅持到2038年),由于32位時間戳是10位十進制整數(最大值4294967295),所以我們讓時間戳占據低10位(十進制整數),實際分數則擴大10^10倍,然后把兩部分相加的結果作為zset的分數。考慮到要按時間倒序排列,所以時間戳這部分需要顛倒一下,這便是用9999999999減去時間戳的原因。當我們要讀取玩家實際分數時,只需去掉后10位即可。

初步看起來這個方案還不錯,但這里面有兩個問題。

第一個問題是小問題,采用秒為時間戳可能區分度還不夠,如果同一秒出現兩個分數相同的仍然會出現前面的問題,當然我們可以選擇精度更高的時間戳,但在實際場景中,同一秒誰排前面已經無關緊要。

第二個問題是大問題,因為Redis的分數類型采用的是double,64位雙精度浮點數只有52位有效數字,它能精確表達的整數范圍為-2^53到2^53,最高只能表示16位十進制整數(最大值為9007199254740992,其實連16位也不能完整表示)。這就是說,如果前面時間戳占了10位的話,分數就只剩下6位了,這對于某些排行榜分數來說是不夠用的。我們可以考慮縮減時間戳位數,比如從2015年1月1日開始計時,但這仍然增加不了幾位。或者減少區分度,以分鐘、小時來作為時間戳單位。

如果Redis的分數類型為int64,我們就沒有上面的煩惱。說到這里,其實Redis真應該再額外提供一個int64類型的ZSet,但目前只能是幻想,除非自己改其源碼。

既然Redis也不能完美解決排行榜問題,那最終是不是有必要自己實現一個專門的排行榜數據結構呢?畢竟實際應用中的排行榜有很多可以優化的地方,比玩家呈金字塔分布,越是低分段玩家數量越多,同一分數擁有大量玩家,玩家增加一分都可能超越很多玩家,這就為優化提供了可能。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。

原文鏈接:https://juejin.im/post/5c876854f265da2d9e179112

延伸 · 閱讀

精彩推薦
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
主站蜘蛛池模板: 高清一区高清二区视频 | 免费看60分钟大片视频播放 | 国产成人毛片 | 日产乱码卡1卡2卡三卡四在线 | 成人一区二区丝袜美腿 | 天天综合网天天做天天受 | 美女的隐私无遮挡的网页 | 美女扒开胸罩露出胸大乳 | 美女张开腿让男人桶的 视频 | 极品91| 麻豆网| h高潮娇喘抽搐 | 三级午夜宅宅伦不卡在线 | 特黄特色大片免费视频播放 | 成人免费播放器 | 国产精品伊人 | 美国玩尿眼道videos | 干妞网免费视频 | 亚洲美女爱爱 | 四虎永久在线精品国产馆v视影院 | 欧美1级 | 视频在线播放 | 国产美女极品免费视频 | 亚洲香蕉伊在人在线观看9 亚洲系列国产系列 | 草莓视频网站18勿进 | 亚洲AV无码国产精品午夜久久 | 精品一区二区三区视频 | 男人狂擦女人的下面视频 | 我的年轻漂亮继坶三级 | 色淫阁小说 | 国产成人99久久亚洲综合精品 | 欧美成人福利 | 亚洲系列国产系列 | 国产精品乱码高清在线观看 | 欧美色图亚洲 | 日韩 国产 欧美 精品 在线 | 日韩久久精品 | 强女明星系列小说 | 日本-区二区三区免费精品 日本破处 | nhdta系列媚药系列 | 亚洲精品国产一区二区在线 |