背景介绍
众所周知,在互联网项目中,我们用Redis的场景非常之多,Redis的出现,很大程度补偿了memcached这类key/value存储的不足,
在部分场合可以对关系数据库起到很好的补充作用,使用起来也是非常的方便,多种数据结构让你能更加优雅、轻松的面对各种场景,公司主要做直播行业的,
单纯Redis实例就有上百台,所以这边用Redis也是很频繁的,下面将介绍如果用Redis简易、轻松的去实现各种榜单。
场景模拟
1.日榜实现
假如有一个活动需求,需要你统计每天每个直播间收礼榜单以及贡献者榜单,思考下,你会怎么做?
嗯,聪明的你3秒钟不到就已经想到了要使用Redis的有序列表来进行统计,
没错,Redis的有序列表基本能实现大多的榜单统计功能,下面咱们先拿这个简单需求来开刀。
1.设计数据结构
字段名称定义(member):
{
直播房间ID:roomId, 贡献者ID:userId
}
虽然贡献者可以在每个房间上榜,但房间ID唯一,所以根据这两ID组合可保证唯一性
根据当地时间作为KEY(key)例如 20210630 确保每一天榜单
送礼总价值(score):这个玩意是异步处理的,所以确保每次计算就行了
2.操作
ZADD key score member
至此完事
3.查询
ZREVRANGE key start stop
这样子就将每天的榜单查询出来了,so easy!
2.周榜实现
单纯按自然周来统计的话,跟日榜没啥区别,如果时最近N日榜单,假设继续上面的活动需求,不仅要每日榜单,还需要看近N日的榜单,这时你会怎么弄?
你要是存在数据库里,这个问题非常的好办,直接SQL按时间周期查就完事了,
当然这种高频热点数据你反复在库里读写简直就是找死。
由于Redis这玩意是非关系型,好家伙这时你可能会把每一天数据查出来然后再统一排序?
这种方式当然不可取,首先每天的数据榜单都是一个独立KEY,每个KEY的member和score都是不同的,这种方式虽然可实现,但整体接口响应时间...
前期数据少可能没啥影响,一但量大了,这就是挖坑,后面还得自己填。
正确做法是使用redis有序列表自带的合并操作
命令:
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
别看命令这么长啊,其实很简单:
destination:目标KEY 这里命名一个新KEY,用于查询近N日榜单的KEY
key:你可以填当日
numkeys:要合并KEY的数量 查询近N-1天,这里填N-1
[key ...]:要合并KEY名称数组 N天前除了当日的KEY名称
WEIGHTS: 乘法因子
AGGREGATE:聚合的方式,我们这边计算的是总榜所以使用SUM
当然,你用redis封装的库的API使用起来更加简单、优雅
合并操作时间复杂度:O(N)+O(M log(M)), N 为给定有序集基数的总和, M 为结果集的基数。
总结
采用Redis实现榜单具有天然的优势,其丰富的数据结构,简易使用的API让我们能轻松实现一个榜单功能,当然用的时候也要注意以下几个问题
- 使用时缓存击穿与缓存穿透的问题
- Redis宕机(主从、集群架构下基本很少出现)、 Redis服务不可用时的预案处理
- 缓存一致性问题
路漫漫其修远兮,吾愿与君上下而求索,非常感谢各位帅哥、靓妹的点赞、收藏和评论,关注我,只实战不理论,我们下期见