前言:
  之前写过排行榜的设计和实现, 不同需求其背后的架构和设计模型也不一样.
  平台差异, 有的立足于游戏平台, 为多个应用提供服务, 有的仅限于单个游戏.排名范围差异, 有的面向全局排名, 有的只做朋友圈排名. 实时性差异, 离线统计有之, 实时排名更常见.
  不管如何, 本文将结合之前写的网页闯关游戏, 来具体阐述基于redis排行榜的实战过程.

相关文章系列:
  之前写过两篇关于排行榜的文章, 不过那是针对游戏平台(类似微信, 手Q等)而言的. 每个用户都有自己的排行榜, 不是全局性的.
  • 社交游戏的排行榜设计和实现(1)
  • 社交游戏的排行榜设计和实现(2)
针对游戏全局排行版的文章
基于redis的排行榜设计和实现
需求说明:
以闯关游戏为例, 其排行榜是基于玩家的闯关个数来进行排名的, 这是合乎合理. 但是若两个玩家得分相同, 这种场景又该如何评定呢?
有一种思路是, 当得分相同时, 以玩家最近一关的破解时间来排定, 既鼓励准确率, 又鼓励速度. 换句话说, score(得分)为第一排序因素, time(破解时间)为第二排序因素.
然而, 如果采用redis的sorted set去实现, 只能设定单一的排序分值score. 这样的话, 二级排序想借助redis, 似乎这条路行不通.
不要灰心, 梦想是有的, 万一实现了呢? ^_^.
是的, 解决方案是有的, 先卖个关子, 且看下面分解. 同时也来分析下, 使用redis较之mysql的优势在哪?
mysql方案:
玩家每闯过一关, 需要记录其在该关的得分记录. 另一方面玩家是存在重复闯关的行为, 因此在设计得分模型中, 该得分记录也帮助去重.
闯关记录数据模型
    CREATE TABLE IF NOT EXISTS `tb_game_record` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` varchar(32) NOT NULL COMMENT '用户标识',
`gateid` int(11) NOT NULL COMMENT '关卡编号',
`slove_time` bigint(20) NOT NULL COMMENT '解决时间点',
PRIMARY KEY (`id`),
UNIQUE KEY `userid` (`userid`,`gateid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
    注: userid表示用户, gateid为关卡编号, slove_time为解决的时间点. userid+gateid是联合唯一索引, 用于去重.
根据单纯的依赖这个数据表的设计, top-n查询会如何演化.
排行榜查询类似于Top-N, 其SQL表达有些复杂, 为一个嵌套的子查询.
1). 统计闯关数和最晚破关时间点
    SELECT userid, COUNT(gateid) AS score, MAX(slove_time) AS last_slove_time
FROM tb_game_record
GROUP BY userid
    2). 进行排序(按得分降序, 时间升序)
    SELECT useid, score, last_slove_time
FROM (...)
ORDER BY score DESC, last_slove_time ASC
    3). 整合的SQL+区间段
  SELECT userid, score, last_slove_time
FROM (
SELECT userid, COUNT(gateid) AS score, MAX(slove_time) AS last_slove_time
FROM tb_game_record
GROUP BY userid
) t
ORDER BY score DESC, last_slove_time ASC
LIMIT ?, ?
    总的来说, 还是比较顺利的, 但是性能如何呢? 我们来做一下explain评估.

  

    子SQL使用到filesort, 这个是很耗性能, 但确实也无可奈何.
那有没有改进的方案呢? 当然有, 为何不单独引入一个得分表呢?
总得分记录数据模型
  CREATE TABLE IF NOT EXISTS `tb_game_score` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` varchar(32) NOT NULL,
`score` int(11) NOT NULL,
`last_slove_time` bigint(20) NOT NULL,
UNIQUE KEY `id` (`id`),
UNIQUE KEY `userid` (`userid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    注: score为记录的userid总得分.
每当玩家破解一关的时候, 就自动添加一, 虽然有所写消耗, 但对于查询top-n, 则帮了很大的忙.
TOP-N的查询SQL演变为:
    SELECT userid, score, last_slove_time
FROM tb_game_score
ORDER BY score DESC, last_slove_time ASC
    如果使用explain进行sql分析:

  

    虽然也使用到了filesort, 但其数据规模却比tb_game_record少了一个数量级.
当然它也引入了数据一致性的风险, 因此更新的时候需要做事务上的保护.
redis+mysql方案:
引入总得分记录表, 在查询上还是有一定性能损失的. redis被誉为内存数据结构服务器, 能否代替mysql+cache的功能呢?
至少在排行榜的功能上, 其数据结构sorted set是完全可以满足要求的. 其可以代替得分记录表, ^_^.
当然其难点在于二级排序的模型抽象, sorted set只支持一级排序(sorted set的score域为double类型), 所以问题就演变为能否构建一个映射函数, 把二级排序映射为一级排序(double域).
幸好在排行榜的需求上, 二级排序(score, time)是可以映射为一级排序的(sorted set的score)域.
可以简单设定:
score(得分)+time(9999999999-unix的纪元秒, 且固定长度)
    注: unix的纪元秒, 在可预见的将来, 时间长度都是固定长度的, 且取负. score在前, time在后.
比如玩家A的得分为10, 最后闯关的关卡时间为2016/3/30 17:35:47, 则时间戳为:1459330547. 最终为:8540669452=9999999999 - 1459330547.
最后的sorted set的score得分值为: .
    这样就能完美的到达初期设定的二级排序的排行榜需求了.
映射函数设计注意点
这个其实很重要, 因为sorted set的score是double域, 其表达的精度其实是有所限制的. 如果超过这个精度限度, 那么无论几级排序都是没有意义的.
Double 域的表示
    1bit(符号位)
11bits(指数位)
52bits(尾数位) value of floating-point = significand x base ^ exponent , with sign
(浮点) 数值 = 尾数 × 底数 ^ 指数,(附加正负号)
    而2^52, 2^52 = 4503599627370496,一共16位,理论上, double的绝对精度为15位.
在映射函数中, 切记15位的上限限定. 之前的设定排行榜的排序映射, 总共为12位(2位游戏得分值, 10位unix纪元秒数), 这是满足要求的.
总结:
网上对redis sorted set用于排行榜的文章很多, 但真正的案列解说并不多. 可能这种多级排序在应用中, 更常见.

公众号&游戏站点:
  个人微信公众号: 木目的H5游戏世界

  

  个人游戏作品集站点(尚在建设中...): www.mmxfgame.com,  也可直接ip访问http://120.26.221.54/.

基于redis排行榜的实战总结的更多相关文章

  1. 想知道谁是你的最佳用户?基于Redis实现排行榜周期榜与最近N期榜

    本文由云+社区发表 前言 业务已基于Redis实现了一个高可用的排行榜服务,长期以来相安无事.有一天,产品说:我要一个按周排名的排行榜,以反映本周内用户的活跃情况.于是周榜(按周重置更新的榜单)诞生了 ...

  2. Java实现排行榜基于Redis

    访问我的博客 前言 排行榜作为互联网应用中几乎必不可少的一个元素,其能够勾起人类自身对比的欲望,从而来增加商品的销量.排行榜的实现方式基本大同小异,大部分都基于 Redis 的有序集合 sorted ...

  3. Tomcat7基于Redis的Session共享实战二

    目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无 ...

  4. 不用找了,基于 Redis 的分布式锁实战来了!

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 作者:菜蚜 my.oschina.net/wnjustdoit/blog/1606215 前言:在分布式环境中,我们经常使用 ...

  5. 从Redis分布式缓存实战入手到底层原理分析、面面俱到覆盖大厂面试考点

    概述 官方说明 Redis官网 https://redis.io/ 最新版本6.2.6 Redis中文官网 http://www.redis.cn/ 不过中文官网的同步更新维护相对要滞后不少时间,但对 ...

  6. Redis入门到实战

    一.Redis基础 Redis所有的命令都可以去官方网站查看 1.基本命令 keys * 查找所有符合给定模式pattern(正则表达式)的 key .可以进行模糊匹配 del key1,key2,. ...

  7. 《Netty Zookeeper Redis 高并发实战》 图书简介

    <Netty Zookeeper Redis 高并发实战> 图书简介 本书为 高并发社群 -- 疯狂创客圈 倾力编著, 高度剖析底层原理,深度解读面试难题 疯狂创客圈 Java 高并发[ ...

  8. ASP.NET Core WebApi基于Redis实现Token接口安全认证

    一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebSer ...

  9. 二、Redis基本操作——String(实战篇)

    小喵万万没想到,上一篇博客,居然已经被阅读600次了!!!让小喵感觉压力颇大.万一有写错的地方,岂不是会误导很多筒子们.所以,恳请大家,如果看到小喵的博客有什么不对的地方,请尽快指正!谢谢! 小喵的唠 ...

随机推荐

  1. Listview中显示不同的视图布局

    import java.util.ArrayList; import android.app.Activity;import android.content.Context;import androi ...

  2. Web安全

    随着Web2.0.网络社交等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中,越来越多的应用都架设在Web平台上.Web业务的迅速发展吸引了黑客们的强烈关注,接踵 ...

  3. 在一个老外微信PM的眼中,中国移动App UI那些事儿

    本文编译自Dan Grover的博客,他现在是腾讯微信的产品经理.以下是他从旧金山搬到广州后的近半年时间里,在试用过微信微博等中国主流移动App后,总结出的中美App在设计理念上的差异,并对中国移动A ...

  4. TortoiseSVN文件夹及文件图标不显示解决方法

              由于自己的电脑是win7(64位)的,系统安装TortoiseSVN之后,其他的功能都能正常的使用,但是就是文件夹或文件夹的左下角就是不显示图标,这个问题前一段时间就遇到了(那个时 ...

  5. JPA原理理解

    从前面一篇<JPA使用入门>了解了JPA的简单使用.要想继续深入的使用JPA,可能了解一点原理对于学习JPA会比较有益处. 这里从JPA的功能来简单阐述JPA的原理. 从<初步了解J ...

  6. Theoretical comparison between the Gini Index and Information Gain criteria

    Knowledge Discovery in Databases (KDD) is an active and important research area with the promise for ...

  7. MySQL主从复制与读写分离

    MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践 Mysql作为目前世界上使用最广泛的免费数据库,相信所有从事系统运维的工程师都一定接触过.但在实际的生产环境中, ...

  8. mySQL基本操作学习笔记(一)

                                                                                                        ...

  9. Qt中文乱码解决思路

    最近项目中遇到不少的Qt中文乱码的问题,主要原因是客户的需求比较多,Qt版本有用4的版本的也有用5的版本,并且还有windows与linux跨平台的需求.经常出现个问题是windows的解决了,源代码 ...

  10. elasticsearch,python包pyes进行的处理

    elasticsearch:高性能搜索引擎,官网:https://www.elastic.co/products/elasticsearch/ 对于它相信大家都不陌生,es的使用已经广泛存在 各大网站 ...