一、下单业务流程分析
订单确认 、下订单(锁库存-创建支付宝订单-生成支付二维码)、扫码支付、异步回调-修改订单状态、查看支付订单
下单后减库存,而不是在付款是减库存(以防1000个人准备下单,提示下单成功,但是准备付款的时候却提示因为库存不足而付款失败,用户心态崩了)
下单后不付款咋办?非秒杀商品,下单后不付款那么24h后取消,秒杀商品 10min后取消。
或者我自己觉得可以在支付页面那里加一个倒计时60s的页面,超时不付款就拜拜。。。
二、如何解决超卖
超卖:订单数量多于商品真实库存数
怎么解决:
1、悲观锁:事务之内,加上行锁 仅innodb支持
Select count from product where id = 37 for update;
只有拿到行锁的才能执行,其他的全部阻塞在数据库上。
随着线程不断增大,可能因为这一个行锁就把DB给打挂了,线程一个一个的执行。
效率不行。。。
2、乐观锁:了解下?
加一个version字段,版本号
锁的粒度更细,执行语句的一瞬间,比对一下原来的库里面,CAS原理,总有个先后吧…
问题:用version T0,T1,T2取抢,T0抢到了,T3 T4 T5 (T3抢到了,但是T1 T2 不乐意了)可能出现后到的先抢到秒杀商品(抢红包不能用,秒杀可用)
乐观锁也会影响性能,Innodb能执行事务,事务回滚时,redolog undolog binlog 都需要维护。
3、那咋玩?
防止超卖,根据Sql语句控制,就是类似于我在执行update操作的时候,这一行是一个事务(默认加了排他锁)。这一行不能被任何其他线程修改和读写就是控制,别超过库存数了,悠着点来。再配合事务以及排他锁。
三、下单业务高并发优化思路
前提:10个人进来下单了,库存以及卖完了,其他请求进来已经无意义了
所以也给下单这块咱们来个二级缓存呗
一级缓存部分:
本地Cache中,首先走一下判断当前商品库存是否为0(标识无库存为true?),如果为true则不能下单了。那么下次再有请求直接打到本地JVM中,直接返回false,不用再走逻辑了,更快。
二级缓存部分
下单这个请求没必要全部打到DB上,可以把秒杀商品的库存先放在redis里,可以做预减。
redis的 Decr的操作。
如果库存<0则,再把库存加回去,再返回个false 为啥呢?(补偿机制),以防出现少卖。并且向本地cache中标记该商品无货了(标识无库存为true)
四、高并发场景下存在的问题(少卖)
1、Redis预剪了库存,继续执行下面的逻辑,突然出现异常了,也就是数据库中并没减,那我是不是应该把库存再加回去(通过catch执行),也就是说,redis中的库存信息会加1,同时本地Cache中((标识无库存为true)
2、但是本地的JVM也只能改本地的,不能改其他JVM的订单服务(解决思路:使用redis的发布订阅模式,创建一个channel,像里面发布消息,订单服务群各个服务去监听channel) 还有网络抖动等问题(某个服务没收到,因为channel无ACK机制)