利用数据库行级锁处理并发问题
- 生产问题基围虾超卖问题分析:
- 现象上位机库存18份,但是小程序卖了21份,超卖了3份
- 分析思路
- 针对sku库存的操作:
- 目前有order微服务下单(减库存)
- order微服务取消订单(加库存)
- ops系统上报库存(加库存)
- ops系统人工取餐(减库存)
- 然后查看order下单日志和ops上报库存的日志,发现两边存在同一时刻(毫秒级)针对同一个商品一个加库存,一个减库存,并且都是先读后更新的方式操作DB
-
如是得出下图图
-
此处存在数据脏读(ops最后一个事物脏读),导致最终更新sku库存的时候数据对不上
-
- 针对sku库存的操作:
- 解决方案:
- 利用redis,使用分布式锁,从sku的数据读取就加上锁,最后事物提交之后解锁(编码较为复杂,没有深入讨论,暂不考虑这种方式)
- 利用mysql自带的行级锁,在更新sku的库存时,采用数据库的自增方式(编码简单,也较为轻量级,经过讨论,采用这种方式)
- order微服务相关代码改动点
- 去掉取餐时间的判断
- 这里使用了分布式锁,但是解锁时间太早,属于无效锁,直接去掉
- sku的库存更新,改为数据库自增方式(同理ops也需要同步改为这种方式)
- 尽量让这个sku更新操作早点提交事物,缩短行级锁的时间,防止其他的sku更新操作事物超时