最近一直没有更新博客,刚跳槽到一家做电商的公司,刚进来就接受了秒杀,团购和砍价的高并发任务

在搞秒杀抢购业务,考虑到秒杀会频繁扣减库存和回滚库存 ,会占用数据库资源,转而使用了redis做库存预扣减,然后在开发过程中遇到了些问题,发现网络上的redis做最终一致性很垃圾,根本没考虑回滚失败后如何保证预扣减库存的最终一致,就会导致出现超卖情况,我猜想可能是这方面的东西值钱(自卖自夸一下,哈哈),好了,开始正文

温馨提示,如果只想知道如何保证回滚一致性的问题,直接看解决方案

问题:
问题是这样出现的,在回滚的的时候,如果服务器重启,而且重启的时候正好是redis更新成功,而修改订单由于mysql事务会自动回滚,幂等也没有记录成功,此时就会出现预扣减库存错乱

  1. 实现技术:
    一.redis实现了延迟队列
    二.rocketmq 延迟消息
  2. 业务实现
    一.添加秒杀活动:
          将所有限制的sku库存存储到redis,key是秒杀id,value是库存,然后发送活动结束消息,利用redis延迟队列,活动结束后进行所有未支付的预扣减库存回滚(这个活动结束取消订单是产品狗提出来的需求,扫redis总比扫库强,如果你这里没有这样的需求,就不用实现redis延迟队列,可能有人问了,这里什么没有直接使用rocketmq做延迟消息,反而使用reidis呢,答案很简单,由于rocketmq延迟等级是死的,活动结束时间是很随意的)
    二.开始秒杀
          redis实现分布式锁,我这里是实现了半阻塞锁(温馨提示:最好的方式是通过lua来实现扣减库存,这样就不用加锁了,我们用户量小,就懒得直接用分布式半阻塞锁了), 通过秒杀id redis库存进行扣减,秒杀成功记录秒杀记录,然后利用rocketmq发送rocketmq延迟消息,用于秒杀10分钟后取消未支付订单

可能有人不理解
此处多啰嗦一句 就是预扣减是在提交订单前获取的接口,预扣减只操作redis ,不操作数据库库存,预扣减成功后,才能提交订单 提交订单时,才会操作数据库库存扣减

三.预扣减库存回滚
	到这里,大家可以看到,业务中我用到了rocketmq ,mq本身有重试补偿机制,这里就不说mq的补偿了,比较简单,判断一下重试次数,然后记录重试失败的记录,最后人工补偿就可以了,最后是预扣减库存补偿,看下面的解决方案!

解决方案:

reids 预扣减补偿就有些恶心了,需要用代码补偿,很简单,就是个逆向思维,在每次redis执行进行回滚之前,校验一下redis售出库存==真实售出库存,如果发现 redis售出库存!=真实售出库存,这时候先重置预扣减库存为真实售出库存,在进行回滚就实现了redis预扣减的最终一致性

觉得有效给小弟点个赞,我的博客的动力就是你的点赞 😊
可以关注下博主的公众号,实时推送解决方案!
公众号

Logo

更多推荐