帖子回复列表缓存优化日志

Posted 贝聊技术团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了帖子回复列表缓存优化日志相关的知识,希望对你有一定的参考价值。

尝试写点工作日志,也算是对平日工作的一些思考和总结。这次主要谈谈刚加入贝聊时接下的一个工作任务,对帖子回复列表接口做优化。

一、业务场景

类似于论坛、社区,有各种各样的帖子,用户可以在帖子下回复互动。

二、现状

目前帖子回复列表接口只对前两页数据做缓存,缓存时间为五分钟,string数据结构。当有新回复或者其它更新操作,则删除缓存。

三、存在问题

只对前两页做缓存,其它页都是直接从DB获取,遇到比较火的帖子会有大量请求到达DB,给DB造成压力。

四、目标

在尽可能少改动的前提下,提高帖子回复列表接口的缓存命中率,让绝大部分请求都能直接从缓存返回,减轻DB压力。

五、设计

使用Redis的Sorted Sets结构缓存帖子的回复信息,回复id当score,回复信息当member。

用增量方式更新缓存,有新回复,直接追加到sortedSet。同样,若删除回复,从Sorted Sets中移走该条回复。

利用Sorted Sets的排序功能,可直接获取某一页的数据返回。

说明:

1、考虑到实际场景,这里并没有缓存某个帖子所有的回复列表。因为用户翻查回复列表,大多数集中在前面几页,后面的极少会翻到,所以我们只缓存了400条数据,按一页20条数据,即20页。如果是超出20页的请求,则直接从DB获取数据返回。

2、帖子回复列表根据回复时间排序,新帖子在前面展示。这里用id当score,是因为我们的回复列表id是自增的,严格与回复创建时间保持一致的顺序。通过ZREVRANGE命令从大到小返回。

若id非自增,可以用回复时间当score。不过时间可能存在重复,若两个回复的时间一致,在查询列表时不存在问题,只是在删除具体某个回复时,不能通过ZREMRANGEBYSCORE命令删除(相同时间不能唯一确定一条回复数据)。

六、优点

1、在更新频繁情况下,依然能保持缓存高命中率。

例如运营在搞盖楼活动时,用户都在抢楼,帖子回复列表更新频繁。如果按之前方案,则前两页缓存会处于“建立-删除-建立”这么一个循环当中,命中率很低。同时还会有大量非前两页请求,DB压力非常大。

新方案是对缓存做增量更新,即使用户拼命抢楼,也能保证前面20页的数据命中缓存,减低DB压力。

2、在访问非前两页数据时,也能命中缓存。

虽然非前两页的请求量相对要低,但在总请求量很大的情况下,穿透缓存访问DB的量还是需要考虑的。这里提供前面20页的缓存,基本覆盖绝大部分请求。毕竟用户在一个帖子下翻了几十页的回复,这种情况基本没有。同时,在产品上,最好不要提供直接跳转第几页的功能。

七、优化前后数据对比

14号上线,对比上线前后4天的统计数据如下帖子回复列表缓存优化日志帖子回复列表缓存优化日志八、可能存在的问题

1、数据一致性:

若在增量更新缓存时操作失败,则缓存数据会跟DB数据不一致。

可以通过增加重试机制,降低概率。

或者先更新缓存,发布一个消息到消息队列,异步更新DB。

2、在缓存过期的瞬间,如果并发很高,可能存在多个请求做同样的操作(从DB获取数据,再set到缓存)

可以通过设置一个全局的标记位,若标记位已设置,则只执行从DB获取数据,不需要set到缓存。保证同时只有一个线程在执行set到缓存这一操作。

当然,若不作处理,对数据也无影响。

3、同样在缓存过期的瞬间,若同时存在查询和回复帖子操作,则有可能导致数据不一致

举个例子:

线程A查询列表,发现当前缓存不存在,则从DB获取数据,然后set到缓存。同时,线程B新增一回复,发现当前缓存不存在,直接更新DB。则有可能线程A set到缓存的数据没有包括线程B新增的回复。简单画个图如下:

解决方案:

将添加回复数据记录下来,在线程A将回复列表set到缓存后执行一个回调,将新增加的回复数据更新到缓存。补充:

(1)如果线程A获取的数据已经包含了新回复数据newReply,则线程在执行回调时会重复添加newReply数据到缓存,不过Sorted Set会自动识别为同一条数据,对结果无影响。

(2)如果线程A在线程B记录下回复数据newReply前就完成执行回调操作(此时newReply数据为空),则会导致DB、缓存数据不一致。

针对第(2)种情况,可以考虑在线程A执行完“将数据列表set到缓存”操作后,延时执行回调(例如5秒),基本可以解决此类问题。

4、若业务对此类数据没有强一致性要求,则以上三点均可不考虑。


以上是关于帖子回复列表缓存优化日志的主要内容,如果未能解决你的问题,请参考以下文章

如何优化我的查询?使用类别和标签列表导出 Wordpress 帖子

redis应用场景

我可以从缓存中加载后退按钮吗?

PRAW:回复帖子

寻找水王

梦幻星球社区APP源码 HYBBS的iApp社区源码