✅有100个优惠券,有几千万流量,怎么保证服务器不跨掉,怎么保证最前面的人能抢到这个券?
典型回答
这是一个典型的秒杀问题。几千万个并发抢100个库存,如何保证不超卖、不少卖,如何保证服务不被打垮、如何保证前面的人能抢到,这都是秒杀系统需要考虑的重点问题。
超卖:一共100件,卖出去101件
少卖:一共100件,只卖出去99件,另外的那一件无法购买了
关于优惠券的库存的超卖和少卖的问题,可以看一下其他的文档,内容都是一样的方案。
✅账户里面只有十块钱,同时发来两笔订单一共大于十块钱,怎么保证不超花?
这里重点说一下如何保证前面的人能抢到。
这个其实就是我们多次提到过的,要用Redis来做扣减,而不是直接用加分布式锁和限流来实现秒杀的主要原因。
因为如果使用限流,那么没办法保证被限制住的流量是先来的还是后来的,因为有可能非常极限的他们差个零点几毫秒,但是限流其实是按照秒级做统计和限制的,所以一秒内的请求一起过来的时候,谁能被放过,谁能被阻塞,就靠运气了。
分布式锁也是一样的,需要靠抢锁来获取库存扣减的资格,但是并不能保证先来的一定能抢到锁,因为有可能当前有人在持有这个锁,而后来的线程可能来的时候刚好没锁,就很快就拿到了。
而如果借助Redis的lua脚本或者事务进行库存扣减,那么Redis可以保证命令执行的先后顺序,按照发送顺序进行执行,先来的请求就能先进行库存扣减了。扣减成功则说明有库存,那么就可以给他发放优惠券了。(操作数据库)
当库存扣减为0之后,后续的请求再进来,会在Redis中构建失败,因为库存已经没有了,无法扣减了,这样就可以把后续的所有流量都抗在数据库之前了。
如果做的再好一点,在redis中维护一个优惠券是否还有库存的表示,先判断是否还有,然后再扣减,或者这个标识也可以维护到本地缓存,可以进一步提升性能,减少应用被打垮的概率。(这个本地缓存的方案在我的项目课中有用到。感兴趣的可以了解下、)