百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>网页制作> PHP+Redis 有序汇合实现 24 小时排名榜实时更新
分享文章到:

PHP+Redis 有序汇合实现 24 小时排名榜实时更新

发布时间:09/01 来源:未知 浏览: 关键词:
根本介绍

Redis 有序汇合和汇合一样也是 string 类型元素的汇合,且不同意反复的成员。

不一样的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为汇合中的成员停止从小到大的排序。

有序汇合的成员是独一的,但分数 (score) 却可以反复。

汇合是通过哈希表实现的,所以增加,删除,查寻的复杂度都是 O (1)。 汇合中最大的成员数为 2^32 - 1^ (4294967295, 每个汇合可储备 40 多亿个成员)。

有序汇合第一是汇合,其成员(member)具有独一性,其次,每个成员关联了一个分数(score),使得成员可以依照分数排序。

需求描写

设想在一个游戏中,有上百万的玩家数据,假如此刻需要你按照玩家的经历值整理一个前 10 名的排行榜,你会如何做呢?一样的做法是写一条相似下面这条 sql 语句的方式来猎取:

    select * from game_socre order by score desc limit 0,20

这种方式在数据量较小的状况下可行,但是在数据量大的状况下查询速度将变慢,特殊是还需要联表查询时,速度下落的就更明显了。

实现

这时你可以思考使用 redis 来实现这个功效。

实现这个功效主要用到的 redis 数据类型是 redis 的有序汇合 zset。zset 是 set 类型的一个扩展,比原有的类型多了一个次序属性。此属性在每次插入数据时会主动调整次序值,包管 value 值依照必然次序持续摆列。

主要的实现思绪是:

1、在一个新的玩家参与到游戏中时,在 redis 中的 zset 中新增一笔记录(记载内容看详细的需求)score 为 0

2、当玩家的经历值发生转变时,修改该玩家的 score 值

3、使用 redis 的 ZREVRANGE 办法猎取排行榜

返回有序集 key 中,指定区间内的成员。其中成员的位置按 score 值递减 (从大到小) 来摆列。具有雷同 score 值的成员按字典序的反序摆列。 除了成员按 score 值递减的次序摆列这一点外,ZREVRANGE 命令的其他方面和 ZRANGE 命令一样。

redis 127.0.0.1:6379> ZADD KEY_NAME SCORE1 VALUE1.. SCOREN VALUEN

1、数据预备

b9c118380d12cbd9350fb4b7f028b3c.png

2、猎取 score 高分 top10 排行 (ZREVRANGE 为落序,ZRANGE 为升序)

1e8c358b8a6d91ebb01119036852138.png

3、查看会员 ee 的实际排行 (ZREVRANK 为落序,ZRANK 为升序)、实时分数

54cae0fd18770201b8dbb09cff6f856.png

进一步需求

需要实现比来的 24 小时会员积分排行榜,并统计前 10 名的玩家和积分

实现

主要的实现思绪是:

利用 ZADD 按小时划分增加会员的积分信息,然后用 ZUNIONSTORE 并集实现 24 小时的游戏积分总和,实现 “24 小时排行榜”;(假如有更好的思绪,能够鄙人方留言不惜赐教一下就更好了)

    ZUNIONSTORE destination numkeys key [key ...]

Redis Zunionstore 命令运算给定的一个或多个有序集的并集,其中给定 key 的数目必需以 numkeys 参数指定,并 将该并集(结果集)贮存到 destination 。

默许状况下,结果集中某个成员的分数值是所有给定集下该成员分数值之和 。

大概碰到的问题

1、雷同分数问题

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,但当前只能是梦想,除非本人改其源码。

更多PHP相关知识,请拜访PHP中文网!

以上就是PHP+Redis 有序汇合实现 24 小时排行榜实时更新的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有153人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板