对于一些数据量较小、业务逻辑相对简单的场景,数据库成为了排行榜设计的首选工具。就拿一个小型比赛的排行榜来说,假设参赛队伍仅有寥寥数支,排行榜表中的数据量始终保持在一个较低的水平。此时,借助数据库的排序功能,如MySQL中的order by
语句,便能轻松实现排行榜的基本功能。
ZSet是Redis中的有序集合数据结构,每个元素(member)都关联一个分数(score),ZSet会根据分数对元素进行排序。元素在集合中唯一,但分数可以相同,当分数相同时,按字典序排列。例如,在一个游戏排行榜中,玩家ID是member,玩家的游戏积分就是score。
ZADD key score member [score member ...]
game_rank:202410
(表示2024年10月的游戏排行榜)的ZSet中添加玩家数据,假设玩家player1
的积分为1000,player2
的积分为1200,命令如下: ZADD game_rank:202410 1000 player1 1200 player2
game_rank:202410
原本为空,执行上述命令后,返回(integer) 2
;若player1
已存在且分数不变,仅添加了player2
,则返回(integer) 1
。ZINCRBY key increment member
player1
在游戏中又获得了200积分,更新其分数的命令为: ZINCRBY game_rank:202410 200 player1
player1
之前分数为1000,执行上述命令后,返回"1200"
。ZRANK
按分数从低到高返回元素排名(排名从0开始),ZREVRANK
按分数从高到低返回排名。ZREVRANK game_rank:202410 player2ZRANK key member
、ZREVRANK key member
player2
在排行榜中的排名,从高到低排名命令如下:nil
。比如player2
在game_rank:202410
中排名第2(从高到低且排名从0开始),则返回(integer) 1
;若player2
不存在,返回(nil)
。ZRANGE
按分数从低到高返回指定排名范围内的元素,ZREVRANGE
按分数从高到低返回。可通过withscores
参数返回元素及其分数。ZREVRANGE game_rank:202410 0 2 withscoresZRANGE key start end [withscores]
、ZREVRANGE key start end [withscores]
withscores
则同时返回分数。例如,若game_rank:202410
中有player4
(分数1800)、player3
(分数1500)、player5
(分数1200),执行上述命令后,返回值可能为:1) "player4"
2) "1800"
3) "player3"
4) "1500"
5) "player5"
6) "1200"
ZSCORE key member
player1
的分数,命令为:nil
。若player1
分数为1200,返回"1200"
;若player1
不存在于game_rank:202410
中,返回(nil)
。ZREM key member [member ...]
player2
退出游戏,要从排行榜中删除他,命令如下:player2
存在于game_rank:202410
中,执行命令后返回(integer) 1
;若player2
不存在,则返回(integer) 0
。假设我们要构建一个游戏排行榜,记录玩家的积分并实时更新和展示。
game_rank:202410
原本为空,返回(integer) 3
。
2. 更新玩家积分:玩家player3
获得了300积分。ZINCRBY game_rank:202410 300 player3执行该命令后,假设player3
之前积分是1500,返回"1800"
。
3. 获取排行榜信息
获取排行榜前两名玩家及其分数:ZREVRANGE game_rank:202410 0 1 withscores
假设此时game_rank:202410
中有player4
(分数1800)、player3
(分数1800)、player5
(分数1200),返回值可能为:
1) "player4"
2) "1800"
3) "player3"
4) "1800"
player4
的排名:ZREVRANK game_rank:202410 player4
若player4
在game_rank:202410
中排名第1(从高到低且排名从0开始),返回(integer) 0
。
player5
的分数: ZSCORE game_rank:202410 player5
若player5
分数为1200,返回"1200"
。
通过上述Redis的ZSet命令,我们可以高效地实现一个功能完善的排行榜系统,满足实时更新、查询排名和分数等需求。在实际应用中,可根据具体业务场景对这些命令进行灵活组合和扩展。
当面对亿级用户的超大规模排行榜时,传统的设计方案往往显得力不从心。以王者荣耀为例,为了应对如此庞大的用户基数,我们引入了分治思想。首先,根据游戏中的段位将用户进行分组,每个段位如同一个独立的“桶”,对应Redis中的一个key
。通过这种方式,将庞大的用户群体进行了有效的划分,降低了单个排行榜的处理压力。
在每个桶中,我们可以利用Redis的zcard
命令快速获取桶内集合的大小,这一操作的时间复杂度仅为O(1),为后续的排名计算提供了高效的支持。当计算用户的全服排名时,需要综合考虑其在所在桶内的排名以及前面所有桶中的元素个数。例如,一个处于钻石段位的用户,其全服排名等于钻石段位桶内的排名加上前面青铜、白银、黄金等段位桶内的元素总数。
然而,在实际应用中,用户在各个段位的分布往往并不均匀。为了进一步优化排行榜的性能,我们需要对每个桶进行更为细致的划分,比如按照小段位或者积分区间进行细分。同时,借助数据分析手段,深入了解用户的分布规律,运用数学知识精准预估每个桶的大小,从而实现排行榜的高效管理与精准计算。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。