天天看点

热门排行榜-redis实现

      最近项目架构升级,主要对性能方面进行升级。之前热门排行榜是通过对点赞量,阅读量,收藏量等一系列的数据在DB通过计算查出来的,效率方面不太好。因此考虑对该功能进行升级优化,并且添加周期性排行榜如月排行,总排行。

      在引入缓存之后首先考虑的是通过缓存实现热门排行榜的功能,但是考虑到首次引入缓存担心缓存出现问题导致功能不可用。所以在做方案的时候,采用优先使用缓存,如果缓存不可用则走DB。因此DB的设计也需要进行优化。

为方便理解,先将活跃度变化(也就是点赞,收藏,阅读,之后的对应数量的更新)流程图记录下:

热门排行榜-redis实现

       以点赞操作为例,点赞之后没有直接去更新DB活跃度表的数据量,而是去更新缓存中数据(hash)对应的点赞数,因为在操作频繁的情况下更新缓存会比更新DB效率快很多。并且将缓存中被更新数据的key记录下来,记录在redis中设置5分钟过期时间,并且通过setnx命令进行写入,也就是如果该key还没过期你是保存不成功的。这么做的目的是只是把这一步当作一个屏障挡在写入消息之前,只有保存成功才可以进行写入消息,以免频繁的写入消息,如果保存key成功则写入消息,消息的消费端延迟1秒钟去读取消息,其实这就类似于一个周期为1秒的定时任务,读取消息之后可以从消息体中获取key,并通过该key去缓存中找到对应的数据,将数据同步至DB。

     该流程我理解为一个“伪同步数据库的流程”,页面的操作直接更新缓存,而通过可延迟消费消息的中间件异步的将数据更新至数据库。从根本来说来是更新了数据库,并且从时间上来看基本上的同步更新数据库的,但实际是通过消息中间件异步实现的。

总体流程图:

热门排行榜-redis实现

优先从缓存获取,若缓存不可用则走DB。因此对DB设计也需要优化。

DB设计优化

榜之前的点赞数  收藏数  等一系列与活跃度相关的数据存在一张表中,称之为活跃度表,该表的数据量和文章表中的数据量大体上是一样的。并且随着时间积累数据量会越来越大,因此不再这张表中做手脚,新建一张表,新建的表专门用于各种各样的排行。

新建表的主要字段:

1  类型:排行榜类型,如周排行榜,月排行榜。。

2 内容类型:如博客,直播,主播。。。

3 实例ID : 如博客 id,直播code等

4 热度 :活跃度

DB实现排行榜流程

热门排行榜-redis实现

1  定时更新任务(5分钟):从活跃度表中查出所有文章热度最高的前100条数据和当月发布的文章热度最高的前100条,并且将数据同步至新建的排行榜表中,类型分别为 月排行榜和 总排行榜。

2 定时清除任务:在每月的1号0点,将上个月的月排行榜数据置为删除态。

其实排行榜并用不了100条数据,目前要展示的数量远远小于100,为什么要同步100条数据多出要展示的数据量呢?因为考虑到如果热门文章被删除了,排行榜中对应数据也需要被删除,因此同步的数据要多于要展示的数据量。

DB这么设计之后,月排行榜可以直接从这100条数据中根据热度排序取出前几条,查询效率远远比之前要快。并且定时任务是通过 消息中间件+定时器 配合完成的 集群中只有一台服务会进行定时处理数据以免重复处理。

缓存实现排行榜

缓存的数据结构使用 redis的zset实现,因为zset支持根据score进行排序查询。

zset的key为我们自己约定的key,score为文章热度,member为文章数据

热门排行榜-redis实现

1  定时更新任务:同DB一样只不过是更新至 总排行榜的zset和月排行榜的zset

2 定时清除任务:同DB

因此通过缓存查询排行榜可根据排行榜周期性的不同,分别取不同key对应的数据即可。

继续阅读