本文主要是介绍凭证卷发放流程优化方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
背景
上周线上有多个大促活动,创建了多个凭证卷模版,并导入了大量劵码,其中有多个卷模版下的劵码超过50w+, 在发放劵的时候,会先查询一次卷码库存,其中劵模版ID是分库分表键,所以在统一模版下的数据量过多了以后,就会导致慢sql
select * from t_coupon_code from templateId = #{templateId} and status = "未发放" limit 20;
Q&A
Q1: 为什么sql 要写limit 20,直接查一个不行吗?
因为发放过程存在并发问题,玩法系统的RT有要求,不能超过100ms,所以营销获取可用劵码的时候多拿了几条,然后随机返回一条,减缓并发过程中的冲突,就算两个用户拿到了同一个劵码了,在后续的更新流程当中,一定会有一方更新失败,所以不存在两个用户抢到同一张劵码的情况
Q2: 为什么同一模版下,劵码量大了会导致慢SQL?
虽然sql,能够命中索引,但是后面的字段区分度不大,会扫描整个索引树,如果还不懂,建议回归校园
优化方案
引入Redis的set结构
为什么是set不是list?
:::success
List: 也是能够实现这样的效果的,但是需要防止出现重复元素,因为劵码是不会重复的
Set: 不仅能够去重,而且也能随机弹出集合内的元素(时间复杂度O(1))
:::
引入redis以后如何发放劵码
这里只是简单给个思路,我很懒不想画流程图了,在公司天天敲,😡
- 从redis中pop出
- 如果pop的元素不是空,查询数据库 并返回结果
- 如果是空,判断当前劵码是否没有库存了(redis中的一个标记位)
- 如果有库存 加载DB中的数据到缓存,如果没有加载到,说明没有库存了,缓存中记录标记
引入redis以后数据一致性如何保证
会出现短暂的不一致场景:运营删除劵码库存的时候
但是不会有影响,应为pop,出一个已经被删除的元素以后,后续走正常的发放动作,这个过程中更新DB会出现问题,从而避免了并发问题
这篇关于凭证卷发放流程优化方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!