难题,一方面是在正常的系统设计中,其实很少考虑 Redis 崩溃之后应该如何解决,基本都是假设 Redis 是一个高可用的,几乎不会崩溃。另外一方面则是 Redis 是秒杀中的一个比较重要的环节,很多人从来没思考过万一 Redis 崩溃了怎么办。
这个问题的装逼方式有两个:一个是揭示出 Redis 承担的预扣库存这个步骤并不是必不可少的;另外一个则是揭示在秒杀的时候,可以引入随机过程来直接返回秒杀失败的响应。
秒杀架构:如何设计一个秒杀系统? - 面试ICU (mianshi.icu)
Redis 在秒杀系统中承担的是预扣库存的责任,而且它取到的是一个获取资格的作用,那么基本上你就可以猜到,要说它重要吧,确实很重要。要说它不重要吧,其实也没那么重要。
要注意一点,有些人会在这个问题下狡辩说自己部署的是集群,不会崩溃,又或者狡辩自己部署的是主从结构,也不会崩溃。这都不是面试官想要听到的话,毕竟这年头谁家使用 Redis 不是实施了高可用方案呢?
从理论上来说,Redis 一旦崩溃了之后,有多种解决方案。
第一种方案就是限流,但是因为 Redis 已经崩溃了,搞不了集群限流了,所以可以使用单机限流。根据奖品的数量来决定限流的阈值,例如说总共参与秒杀的商品只有 100 个,那么单机限流 100 就够了,甚至于就算有 1000 个商品,那么限流到 200 也可以。
第二种方案就是直接转发秒杀请求到 Kafka 上,借助 Kafka 的削峰效果。而正常来说,Redis 能撑住的流量,Kafka 也是撑得住的,并且就我经验来说 Redis 撑不住的,Kafka 也撑得住。整个过程如图。
你要注意一个点:参与秒杀的商品的库存放在 Redis 的一个 key 上,也就是它只能在 Redis 的一个节点上,那么顶天了上限就是 10w QPS 左右。而 Kafka 是一整个集群都能用上的,所以它能撑住更高的并发。
第三种方案就是根据概率直接判定用户是否秒杀成功。假设说商品有 100 个,但是预期有 1w 人参与抢购,那么基本上可以认为参与秒杀的人也就是在 1% 左右秒杀成功,而后放宽一点加入一些 buffer,那么可以将概率设置在 5%。而后生成一个 [0, 100) 之间随机数 N,如果 N < 5,那么请求就转发到消息队列上,如图。
此外还有一些在面试中可以尝试使用,但是我不建议的。例如说使用双 Redis 集群,它的问题在于难以维护数据一致性。例如说 AB 两个集群都放了库存,那么预扣库存就要在这两个集群上同时扣库存,很容易就出现一个成功一个失败的问题,这种涉及一致性的问题一旦面试官追问就是一场灾难。
那么总结一下: