Redis中SortSet使用不当导致的分页Bug怎么解决

发布时间:2021-09-14 18:13 来源:亿速云 阅读:0 作者:chen 栏目: 服务器

这篇文章主要讲解了“中SortSet使用不当导致的分页Bug怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Redis中SortSet使用不当导致的分页Bug怎么解决”吧!

首先,我们线上的电商系统正在进行一个大促活动。买家非常的多,导致一时间产生了非常多的评论。开发人员在存储(保存)评论时,使用 Redis 中的 SortSet 这个数据结构。每新增一条评论,他都通过 zadd 命令将起保存至 Redis 和 中,查询时直接在 Redis 中取出来。代码抽象一下,如下所示:

顺便说一下,System.currentTimeMillis() 是毫秒,System.currentTimeMillis() / 1000 就相当于精确到秒。

这个活动是大促,参与活动的需要评论。活动比预期的热,导致同一秒的评论就比较多,导致 zrangeByScoreWithScores 在取出评论列表时,遇到同一秒的超过 10 条的评论,就会出现重复数据。

取出评论列表的逻辑大致抽象如下:

看到没?他每次拿 lastScore 记录,也就是上一页评论的最后一条数据的时间。来获取新的 10 条评论数据。由于同一秒评论的记录超过 10 条后,导致每次 APP 每次下拉刷新获取到重复数据的概率比较高。于是就有客户投诉,看评论中的数据都是一样的。无论怎么刷新都是 10 条一样的数据,和上一页的数据一样。

这个 zrangeByScoreWithScores 其实就是 Redis 中的 ZREVRANGEBYSCORE 指令。完整指令如下:

其中这个 limit 是可以分页的。这个分页对下拉刷新也有一个问题,那就是在你下拉刷新时,刚好新增了几个评论,所以刷新出来的数据也可能有重复的数据。

后来这个程序员针对这个问题有改了一下,每次拿到 lastScore 后加 1。我看到这个代码后,又找他了,这个做法肯定不行的。也就是说你每次拿到上一页最后一条的 lastScore 后,再加 1。就相当与时间上加了 1 秒,中间肯定会漏掉一些数据的。

那么该怎么办呢?如果你想使用 lastScore 进行分页,就必须保证它唯一。不然就有概率发生刷新列表时,出现重复数据。

我们这个和时事新闻还有些不一样,新闻的写入时间重复概率没有我们这个高。尤其是我们在大促的活动当中。

最后说一下这个问题的解决办法。一种就是保证 lastScore 唯一,或者说时间在进一步精确。还有一种就是 lastScore + limit 的组合来实现分页。或者就是单纯的使用 limit 来实现,但是也要注意不能刷新出重复数据。

我们的做法,最终是参考了上图。

将每个主题的 topicId 作为 set 的 key,将与该主题关联的评论的 createDate 和 commentId 分别作为 set 的 score 和 member,commentId 的顺序就根据 createDate 的大小进行排列。

当需要查询某个主题某一页的评论时,就可主题的 topicId 通过指令 zrevrange topicId (page-1)×10 (page-1)×10+perPage 这样就能找出某个主题下某一页的按时间排好顺序的所有评论的 commintId。page 为查询第几页的页码,perPage 为每页显示的条数。

当找到所有评论的 commentId 后,就可以把这些 commentId 作为 key 去 Hash 结构中去查询该条评论对应的内容。

这样就利用 SortSet 和 Hash 两种结构在 Redis 中达到了分页和排序的目的。

免责声明:本站发布的内容(图片、视频和文字)以原创、来自本网站内容采集于网络互联网转载等其它媒体和分享为主,内容观点不代表本网站立场,如侵犯了原作者的版权,请告知一经查实,将立刻删除涉嫌侵权内容,联系QQ:712375056。