PHP+Redis 有序集合实现 24 小时排行榜实时更新-php教程

资源魔 30 0
根本引见

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 值依照肯定程序延续陈列。

次要的完成思绪是:

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

二、当玩家的经历值发作变动时,修正该玩家的 score 值

三、应用 redis 的 ZREVRANGE 办法猎取排行榜

前往有序集 key 中,指定区间内的成员。此中成员的地位按 score 值递加 (从年夜到小) 来陈列。具备相反 score 值的成员按字典序的反序陈列。 除了了成员按 score 值递加的秩序陈列这一点外,ZREVRANGE 饬令的其余方面以及 ZRANGE 饬令同样。

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

一、数据预备

b9c118380d12cbd9350fb4b7f028b3c.png

二、猎取 score 高分 top10 排名 (ZREVRANGE 为降序,ZRANGE 为升序)

1e8c358b8a6d91ebb01119036852138.png

三、查看用户 ee 的实际排名 (ZREVRANK 为降序,ZRANK 为升序)、及时分数

54cae0fd18770201b8dbb09cff6f856.png

进一步需要

需求完成比来的 24 小时用户积分排行榜,并统计前 10 名的玩家以及积分

完成

次要的完成思绪是:

行使 ZADD 按小时划分增加用户的积分信息,而后用 ZUNIONSTORE 并集完成 24 小时的游戏积分总以及,完成 “24 小时排行榜”;(假如有更好的思绪,可以正在下方留言不惜见教一下就更好了)

    ZUNIONSTORE destination numkeys key [key ...]

Redis Zunionstore 饬令较量争论给定的一个或多个有序集的并集,此中给定 key 的数目必需以 numkeys 参数指定,并 将该并集(后果集)贮存到 destination 。

默许状况下,后果集中某个成员的分数值是一切给定集下该成员分数值之以及 。

可能碰着的成绩

一、相反分数成绩

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 小时排行榜及时更新的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学 Redis

抱歉,评论功能暂时关闭!