秒杀一般是大流量少库存,像我目前营销活动这块设计到商品库存的周期库存,设计理念就是想让商品慢慢卖,平均到指定周期的指定时段,一般单商品单个周期多了也就200左右并发的样子,一般主要设计的好下单的时候没啥问题;但是呢,这里存在一个未来可能的问题,那就是商品流量确实很大,商品库存也很多,比如100万人抢1W个小米手机,好家伙,完全是真实情况啊,这个问题其实是一个很现实的问题,在真实的做电商的互联网公司其实都会遇到这个问题,但是呢你看很多人的博客,公众号都写的比较夸张,标题都是啥10W并发,一看库存几十个,玩呢老哥,真实有那么大流量的,库存不至于这么低,万一搞个大库存,用你这方案妥妥的宕机啊;
一 . 有效订单的高并发问题描述
我目前做活动商品库存,活动开始前把活动信息和商品库存量预热到redis里去了,10W qps以内基本没问题.
如果方案是扣减时候先lua扣redis,扣成功了同步扣mysql,这样可以解决流量大库存少的问题,基本上库存比较少没有啥问题。
但是这里有个超级漏洞 如果一个商品又有极大的流量,又有大库存的时候,比如10万个人并发抢购10万个商品
那么这里有个超级漏洞 会导致系统直接崩溃,给大家描述一下大概的崩溃流程~~~~
用户下单
👇
redis全部扣减成功,这时候Redis其实就流量拦截个寂寞了,直接形同虚设了
👇
大量的扣减操作直接进入mysql
👇
同一个商品,行级变更扣库存,排他锁被占用
👇
大量的线程在mysql层面进入了阻塞状态
👇
底层数据交互耗时严重,导致服务端的线程陷入阻塞
👇
直至我们服务器线程被完全使用了,最后系统完全不可用 (如果你的下单回滚和其他功能`比如活动信息查询等`在同一个服务上)
👇
`最后系统崩了,全线崩溃超时`
这些都是我们实际开发过程中验证过的,问题很严重
二.如何解决上述问题呢?
这里要明确咱们的底线,可以少卖,不能超卖,超卖就是资损
我这里讲大致思路:利用MQ的分布式事务,先发半消息,扣减的时候直接lua扣redis,同时记录扣减信息(用于mq超时等回查扣减结果),同时向MQ同步扣减信息,做异步扣减
另外我们需要补充一个回查逻辑,用于MQ做确认,什么情况我们需要进行再确认呢?说明:
- 我们不需要考虑过程出现异常的情况,因为如果出现异常,咱们大可以直接触发回滚;
- 我们仅需要考虑提交完半消息,在确认之前出现了任何宕机或者MQ半消息的commit消息丢失了的情况;
真实流程肯定更复杂些,公司的具体流程肯定没办法给大家直接透露的,自己结合自己的情况去看吧;
经过这波优化后,系统的吞吐量其实就已经极大的提高了,如果还担心出现问题,那就尝试结合自己的情况进行数据分组,服务扩容,服务限流吧