高并发|分布式事务锁库存BUG定位

在之前我们做了系统的查询与下单的优化,两个功能都可轻松达到10000QPS+,但是现在高并发下做中转下单(一次性下两个订单)出现了update语句失效或未执行成功的问题。
BUG将会引发的问题:
在使用jmeter工具对下单接口进行压测,两架航班的头等舱库存为100,按照预期当压测结束之后,两架航班的锁定库存数都应该达到100,可进过几轮压测发现,有时可成功锁到100,有时则只能锁到85-99,这就会引出一个问题,在高并发的抢票场景下,50000个人有100个人抢到了票(头等舱的库存为100),按理来说应该库存锁定数为100,则其他人无法进行抢票,可如果锁库存失败,100个人抢到票,但库存锁失败,此时redisson信号量中的库存数也扣减为0了(用户抢票首先判断redisson信号量中是否有库存),那么就会造成数据不一致。因为在用户抢完票后,reidsson信号量中的库存已经被清0,这就代表用户无法继续进行抢票,库存表中的航班上的库存没有锁满,而航班表上的库存已经清0,订单又的的确确出了100个,就会造成数据的不一致性,系统将无法确定那个用户抢到了票,那个用户没有抢到票。
定位BUG:
1.首先观察订单服务在往消息队列投递消息时是否多投递或少投递
高并发|分布式事务锁库存BUG定位
文章图片

在此处打印“投递消息RabbitMQ”信息
高并发|分布式事务锁库存BUG定位
文章图片

头等舱有100个库存,此处可以看到控制台打印确实为100条,则说明投递消息队列时候确实投递了100条消息。接下来看消息队列消费消息数量:
高并发|分布式事务锁库存BUG定位
文章图片

【高并发|分布式事务锁库存BUG定位】从此图可以看到,消息队列接收消息确实为100条,既然投递和消费都没有问题,我们在看新增,如下图所示:
高并发|分布式事务锁库存BUG定位
文章图片

可以看到,新增订单也没有问题,的确是新增了100个订单。新单新增完之后,将会通过openFeign远程调用航班服务进行库存的锁定,我们在到航班服务定位问题。
在锁库存的update语句,我们打印一下消息数量:
高并发|分布式事务锁库存BUG定位
文章图片

查看控制台,我们可以发现,进来的消息数量(code)和sql执行次数(xCode)为200,这里因为我们下的是中转订单,一个订单涉及到两程航班所以100个头等舱的座位,下到两程航班几位200
高并发|分布式事务锁库存BUG定位
文章图片

高并发|分布式事务锁库存BUG定位
文章图片

code和xCode的数量都为200,证明消息数量和sql执行次数没有问题,那么有问题的点可能是sql执行过程,在并发下sql并未成功执行,锁库存业务的设计是sql单条执行的,也就是说,200个订单我们就得执行200次sql,可能早成一些并发问题倒是sql执行失败,因为在xCode打印的时候,打印了2次13。
高并发|分布式事务锁库存BUG定位
文章图片

解决方法:
重新设计业务流程,在订单服务将单条信息消费设计成批量消费,sql的执行可从200次下降到1-2次。

    推荐阅读