需求说明
- 水晶数量排行榜
- 英雄熟练度排版
- 只排前一万名,玩家只能看到前200名的数据和自己的名次
- 每个排行榜实时刷新,玩家可以延迟5分钟查看榜单数据,但是自己的名次需要尽可能实时查看
- 分值一样,则先达到分值的玩家前面在前
设计说明
- 由于要求实时排序,且我们的服务是分布式的,所以采用redis的有序集合sorted set排序
- 将变动分值zadd到集合,然后调用zremrangeByRank移除指定排名区间内的成员,保证只排前一万名
- sorted set支持单字段排序,但是分值一样的时候,需要在比较到达时间,这里使用一个小技巧
score为long类型,但是我们的分值用不到这么大的类型,所以将score的高位表示分值,低位表示距离某个时间点的时间间隔
具体公式如下:score = ((value & 0xfffff) << 32) | (createTime & 0xffffffff)
- 定时拉取前200名的数据到本地内存
注意事项
- 我们的redis没有开启持久化,所以需要将排行榜数据定时备份到数据库。由于是分布式服务,所以需要决定由哪个服务来保存数据,并且需要在redis里记录上次保存时间
这里使用了一个分布式锁,每个服务定时拉取排行榜数据到内存,然后竞争分布式锁,如果获取到锁并且判断上次保存的时间,大于保存间隔时间就执行保存操作
每次保存数据,不是全保存,需要和内存里上次的数据做对比,只保存变化的名次数据,降低写入条数
停服的时候做一次全保存
起服的时候检测redis里是否有排行榜数据,如果没有就需要竞争一个分布式锁,从数据库加载数据到redis - 拉取到内存的排行榜数据立马做好序列化,减少序列化次数
- 限制同一玩家同一榜单数据请求频率(30s),可以减少发送数据次数,降低流量。客户端也可以限制玩家请求数据的频率
- 榜单数据分页发送