秒杀架构改良

刚刚看了一篇比较好的文章,指导怎么构建秒杀系统,看完之后发现有几点可以改良,暂记下来。原文请移步: 点击打开链接

1.去掉乐观锁

由于秒杀活动并发量极高,乐观锁大几率失败,所以这里不考虑乐观锁

2.不使用消息队列

由于设置了限流,实际上系统流量有限,无须使用消息队列。


基于以上,我对秒杀流程进行了改良,思路如下

1.首次访问时,在redis上读取商品的库存,有两种可能: 1.没有读取到库存数量,那只有一种可能,就是秒杀活动刚刚开始。此时需加分布式锁,重新从redis读取库存数,然后把商品库存数缓存到redis,解锁。这里加锁后需重新读取是因为可能有多线程重入读取商品的库存,如果第一个线程已经缓存了商品库存,第二个线程及以后不能重新缓存库存!2.读取到库存为0,秒杀结束,不为0,即还有库存,执行下一步

2.调用redis decr命令使商品库存-1,然后检查命令返回值,返回小于0,即已经没有库存,马上返回失败,返回M (此时M>0),下一步。(由于redis单线程的特点。此处redis decr命令可以保证原子性)

3.增加秒杀订单

4.redis get重新获取商品库存数N,如果最新商品库存数小于M,则不更新数据库(N<M表示刚刚已经有人下单了,redis库存已经减少了,此时更新数据库中商品库存没有意义,比如总库存为10,库存M=9,最新库存值N=8,此时更新商品库存为9没有意义,因为最后始终会更新为8)。如果M=N,加写锁,更新数据库中库存为N,解锁。

伪代码

//加锁    /*在这里加锁是因为:如果在判断M==N之后加锁,另一线程改变了N的值为X(如X=N-1),并且数据库更新最新值为X,之后当前线程继续执行sql更新最新值为N的话会覆盖掉最新的更新!这样会导致修改丢失了,虽然几率极小,但是不可忽略,且此处逻辑简单,加锁对性能影响不大*/

//获取最新库存N

if (M==N){ 

    //执行sql更新

} else{//M>N,执行第四步之前,库存数减少了,此时不更新数据库,什么也不执行

}

//解锁


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值