从数据库随机遍历数据的一次实践

背景

  1. 根据条件,每天给每个用户推荐十名合适的用户(用户当天第一次登录时触发),已经推荐过的不允许再次推荐。
  2. 每天定时给设置了允许自动推荐的用户跑推荐逻辑。
  3. 要求被推荐人具备随机性,满足条件的人都有同等机会被推荐。否则有些人每天被重复推荐多次。

其它解决方案以及利弊

  1. 采用mysql的随机排序函数,每次查出来的数据都不一致,因此达到随机性。缺点采用随机排序的方式,可能会有部分数据始终遍历不到,无法做到极端情况下将所有用户数据都遍历一遍,因此得到的遍历结果如果不满足十人,并不能表示没有十人满足推荐要求。
  2. 一次性将用户数据的userId从数据库全部load出来,并作随机排序。之后根据随机排序后的userId列表遍历。由于load出来的userId列表具备随机性,并且后续查找数据会顺序从列表中分批次查找,这样既具备随机性,又能做到全覆盖查找。缺点是需要查出所有Id,如果用户量大,加上每天有自动推荐的逻辑(一次性需要处理的用户多),对于JVM内存来说也是比较大的负担。

最终解决方案

如下图,在用户表中有6条记录,在逻辑上将表理解成一个环,推荐前随机生成一次下标,指向开始分页的起点random。如果一次分页找三条,先找5和6,然后重置random下标为0,继续往后遍历,直到遍历完整一圈为止。
在这里插入图片描述
这种解决方案既有随机属性,又能在极端情况下遍历所有的用户数据,也不需要将表数据全量load到内存。其实在实践中发现,70%以上的概率只需要分页一次就可以找到十名被推荐人,90%以上概率可以在分页两次内返回。

提高接口的并发处理能力

因为接口存在定时批量推荐的逻辑,可能会由于一次需要处理的数据太多,导致长时间占用系统资源。因此高效的处理方案也是必要的。

  1. 批量推荐前,如果需要推荐的用户太多,需要分批进行推荐,将不同批的人采用负载均衡策略,分布到不同的服务端。
  2. 服务端处理一批推荐人信息时,使用线程池并行处理。

优化点

虽然将数据库理解成“环”后,使得被推荐人都有同等概率被推荐,但是依然需要注意以下几点,避免对性能有较大影响:

  1. 被推荐池子应该具备随机性,即不要让不满足条件的人排在一起,否则一批一批的从数据库load数据的时候,会需要load很多次才能得到结果
  2. 尽可能将匹配条件前置到sql中,使得被推荐人的池子尽可能小
  3. 依然存在小部分人是没有推荐结果的,考虑对每次实时推荐后的结果做缓存
  4. 存在小部分用户接口超时,依然可以采用缓存的方案,使得这些用户第二次进来时,可以马上得到结果
  5. 允许动态调整一次从数据库load的用户个数,配置在nacos这种可以热更新的中间件上,帮助我们根据匹配结果做优化
  6. 对推荐结果需要做监控,缓存重要的匹配信息,如响应时长、一次从数据库load的用户个数、完成一次匹配需要load多少次用户等
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值