✅秒杀场景下,怎么加库存?
典型回答
这是一个非常典型的秒杀相关的问题,秒杀有关的问题,在我的八股文中有多篇都提到过:
✅有100个优惠券,有几千万流量,怎么保证服务器不跨掉,怎么保证最前面的人能抢到这个券?
但是之前讲的主要都是基于库存的扣减的,那么,如果在秒杀期间,想要增加库存该怎么办呢?又需要考虑哪些问题呢?
这个问题看上去好像挺难的。但是如果你想清楚,其实他和库存的扣减是一回事。因为在库存扣减的方案中,我们不管使用数据库也好,Redis也好,都是需要串行进行扣减的,并且库存也是在扣减过程中进行计算的,要么是LUA脚本中计算,要么是SQL语句中计算。
那么,既然高并发的扣减我们都能解决了,那库存的增加还不是一样的道理。我么只需要把扣减的方案一模一样的用到增加库存上就行了。
比如最复杂的Redis+数据库的方案:
1、通过lua脚本进行库存的增加,借助Redis的单线程执行的特性,加上Lua脚本执行的原子性,实现库存的原子性增加。
local key = KEYS[1] -- 商品的键名
local amount = tonumber(ARGV[1]) -- 增加的数量
-- 获取商品当前的库存量
local stock = tonumber(redis.call('get', key))
-- 增加库存并返回新的库存量
redis.call('incrby', key, amount)
return redis.call('get', key)2、发送MQ通知数据库进行库存增加(加库存场景这一步可以省略,但是要做好表单防重复提交)
3、消费MQ,进行数据库的库存的增加,在执行时通过SQL进行库存的增加,即:
update inventory
set quantity = quantity + #{count}
where sku_id='123'如上,Redis的库存增加可以和库存扣减进行排队,靠单线程+Lua脚本原子性。数据库的库存增加也可以可库存扣钱进行排队,靠的是update自带的行级锁。
所以,这个问题就解决了,至于MQ丢失的问题,Redis挂了的问题,和扣减库存其实是一样的。
但是,上面的方案有一个关键前提,那就是需要让增加库存和扣减库存一样,知道我这次要加多少。但是实际上,很多时候库存的修改,并不一定是知道要【加多少】的,只知道我要【加到多少】。所以,这个就需要业务上做取舍了,要么就是在库存设置的后台处,提供【加多少】的增加库存的方式,要么就是以实际增加那一刻为准,算出要加多少,但是这么做可能会在高并发扣减下不准,但是影响其实也不大。