基于Redis的推荐瀑布流

前言:Redis在目前的互联网公司的应用场景非常的丰富,最近公司为了给产品添加社交属性,仿微信的朋友圈做了一个骨人云,包括关注和发现两个频道,再加上本次改版之前的产品首页的五个频道页中的四个频道页,都是推荐的瀑布流,我大量使用Redis的SortedSet,这里记录一下,希望给在处理类型业务场景的同学提供一个方向,因为全是自己摸索的,不知道大厂是怎么做的,有不对的地方欢迎指正。
  1. SortedSet的简介
    • 说SortedSet,要先说一下Redis的另外一个数据类型Set,类似于Java的Set,Set是一个字符串的集合,不允许重复的成员变量出现在一个Set中。而SortedSet和Set类型极为相似,它们之间的主要差别是SortedSet中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。然而需要额外指出的是,尽管SortedSet中的成员必须是唯一的,但是分数(score)却是可以重复的。在Sorted-Set中添加、删除或更新一个成员都是非常快速的操作,其时间复杂度为集合中成员数量的对数。由于SortedSet中的成员在集合中的位置是有序的,因此,即便是访问位于集合中部的成员也仍然是非常高效的。事实上,Redis所具有的这一特征在很多其它类型的数据库中是很难实现的,换句话说,在该点上要想达到和Redis同样的高效,在其它数据库中进行建模是非常困难的。
  2. 应用场景
    • 目前主流的就是排行榜,因为SortedSet自带的排序功能,很容易根据按照根据score从小到大或者从大到小的取出一定数量的数据,还可以根据score的值取值在当前的值范围内的数据。比如我们做全站资源的浏览的排行,我们就可以以资源的ID作为member成员,当资源被浏览一次后使用ZINCRBY给对应资源的score加1,这样我们就可以随时的查询当前时刻排行较前的数据
  3. 推荐瀑布,下面详细列出我的实现步骤
    • 原理:后端接口返回的时候会返回前端返回数据的中的最大的score和最小的score两个值,标识当前用户数据的栈顶和栈底,后续用户通过传递这两个值的其中一个,并且告诉我们是上拉,还是下拉,我们就可以分页取对应的数据,数据图如下
      数据图
    • 步骤:
      1. 用户第一次进入的时候,我们推荐给当前用户的数据是100到115的数据,首屏加载后端返回前端五条数据即110到115,同时返回前端两个score值drop(115)、up(110),前端展示对应数据的时候,同时存储这两个值,这个时候我们推荐给了用户116到124的数据,这个时候没有score值,直接使用zrevrangeWithScores(customerId, 0,5),进行分页取值,
      2. 用户如果执行了下拉动作,需要前端传递115这个score的值,同时告诉我们是下拉动作,我们会返回前端116到120的数据,同时返回前端两个score值drop(120)、up(116),这个时候前端应该更新本地缓存中的值,把drop更新为120,up保持110不变,目前前端一共显示10条数据,根据score值获取大于当前score值的数据,使用zrangeByScoreWithScores(customerId, "115", "+inf")
      3. 如果用户执行了上拉动作,需要前端传递110这个score值,同时告诉我们是下拉动作,后端需要返回105到109的数据,同时返回前端两个score值drop(109)、up(105),这个时候前端应该更新本地缓存中的值,drop保持120,up更新为105,目前前端一共显示15条数据,根据score值获取小于当前score值的数据,使用zrevrangeByScoreWithScores(customerId, "110", "-inf")
      4. 如果用户再一次下拉的时候,前端传递120这个score的值,其他的如2.。。。
    • 原因:为什么需要根据score的来决定获取数据的位置,因为SortedSet中的值,随时有可能会增加和删除,虽然SortedSet本身是支持分页获取数据,但是这个列表随时可能增加或者删除数据,我们根据分页获取的数据,很可能和上次返回给前端的值是包含重复的。比如用户首屏加载了110到115的数据,如果这个时候我们没有给用户推荐数据,下次我们分页取的时候应该是105到109,但是我们把112从这个列表中删除了,那样就会取的是104到108这些数据,这样导致数据丢失。同样如果这个时候我们给用户推荐了116,这个时候上拉的时候分页取第二页的数据,那就取的是106到110,这样前端就会显示出重复的数据了
    • 优化:如果自己站内的资源非常的庞大,并且会不停的推荐给用户,那就要做好定时清理数据的准备,避免SortedSet特别大的情况,我们可以每次在给用户推荐数据的时候,使用ZCARD,计算当前的列表的量,如果超过一定的量可以先删除一部分。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Go语言基于Redis实现的分布式限流是一种常见的解决方案,可以有效地控制系统的并发访问流量,防止系统被过多的请求压垮。 首先,分布式限流需要使用Redis的计数器功能。通过对每个请求进行计数,并设置一个时间窗口,可以统计在该窗口内的请求次数。当请求次数超过某个阈值时,可以拒绝该请求或者进行降级处理。 其次,为了保证分布式限流的准确性和高效性,需要使用Redis的原子操作,例如INCR、EXPIRE等。INCR命令可以原子地将计数器的值加1,并返回加1后的结果,而EXPIRE命令可以设置计数器的过期时间。通过这些原子操作,可以在多个节点之间共享计数状态,并且保证计数器的同步和高效性。 此外,为了保证系统的稳定性和可靠性,需要考虑设置适当的限流阈值和时间窗口大小。根据系统的负载情况和性能需求,可以调整这些参数,实现对系统流量的合理控制。 在实际应用中,可以使用Go语言的Redis客户端连接Redis服务器,并通过相关命令操作计数器。同时,还可以结合其他的组件和技术,如分布式锁、消息队列等,增强系统的稳定性和可扩展性。 总之,Go语言基于Redis实现的分布式限流是一种可行且有效的解决方案,可以帮助我们应对大流量的并发请求,保证系统的稳定运行。通过合理设定限流参数和灵活运用Redis的功能,我们可以实现流量控制、降级和保护系统免受恶意请求的攻击。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值