聊聊秒杀系统的设计(四)

时间:2022-09-21 20:38:36

如果你第一次接触秒杀,可能还不太理解,库存100件就卖100件,在数据库里减到0就好了,这有什么麻烦的?理论上是这样,但是具体到业务场景中就没那么简单了。今天就聊聊减库存的设计,之后以高可用方案来结束秒杀设计的全部内容。


一、秒杀中的减库存

减库存操作一般有如下几个方式:

1.下单减库存:下单后,在商品的总库存中减去购买数量,下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。

2.付款减库存:下单后,并不立即减库存,而是等到付款后才真正减库存,否则库存一直保留给其他买家,但因为付款时才减库存,如果并发比较高,有可能出现买家下单后付不了款的情况,可能商品已经被其他人买走了。

3.预扣库存:下单后,库存为其保留一定的时间, 超过这个时间,库存将会自动释放,释放后其他买家就可以继续购买,在买家付款前,系统会校验该库存是否还有保留,如果没有保留,则再次尝试预扣;如果库存不足则不允许继续付款;如果预扣成功,则完成付款并实际地减去库存,这种方式相对复杂一些。

以上这几种减库存的方式都会存在一些问题。  假如我们采用“下单减库存”的方式,正常情况下,买家下单后付款的概率会很高,所以不会有太大问题,但是有一种场景例外,就是当卖家参加某个活动时,此时活动的有效时间是商品的黄金售卖时间,通过恶意下单的方式将该卖家的商品全部下单,那么这款商品就不能正常售卖了。要知道,这些恶意下单的人是不会真正付款的。

既然“下单减库存”可能导致恶意下单,从而影响卖家的商品销售,那么有没有办法解决呢?你可能会想,采用“付款减库存”的方式是不是就可以了?的确可以,但是 “付款减库存”又会 导致另外一个问题:库存超卖。假如有10件商品,因为下单时不会减库存,就可能出现100人下单成功的情况,这样一 来,就会导致很多买家下单成功但是付不了款,购物体验自然比较差。

既然“下单减库存”和“付款减库存”都有缺点,我们能否采用“预扣库存”这种方式呢? 这种方案确实可以在一定程度上缓解上面的问题,但是否就彻底解决了呢?针对恶意 下单这种情况,虽然把有效的付款时间设置为10分钟,但是恶意买家完全可以在10分钟后再次下单。

针对这种情况,解决办法还是要结合反作弊的措施来制止, 例如,设置最大购买件数,对重复下单不付款的操作进行次数限制等。针对“库存超卖”这种情况,在10分钟时间内下单的数量仍然有可能超过库存数量,遇到这种情况只能区别对待:对普通的商品下单数量超过库存数量的情况,可以通过补货来解决;但是有些卖家完全不允许库存为负数的情况,那只能在买家付款时提示库存不足。

由于参加秒杀的商品成功下单后却不付款的情况比较少,再加上卖家对秒杀商品的库存有严格限制,所以秒杀商品采用“下单减库存”更加合理。一般我们有多种解决方案:一种是在应用程序中通过事务来判断,即保证减后库存不能为负数,否则就回滚;另一种办法是直接设置数据库的字段数据为 无符号整数, 这样减后库存字段值小于零时会直接执行SQL语句来报错。 

二、秒杀中的高可用

高可用涉及架构阶段、编码阶段、测试阶段、运行阶段。

1.架构阶段:架构阶段主要考虑系统的可扩展性和容错性,要避免系统出现单点问题,例如多机房部署,即使某个机房出现整体故障,仍然不会影响整体网站的运转。

2.编码阶段:编码最重要的是保证代码的健壮性,例如涉及远程调用问题时,要设置合理的超时退出机制,防止被其他系统拖垮。

3.测试阶段:测试主要是保证测试用例的覆盖度,保证最坏情况发生时,我们也有相应的处理流 程。

4.运行阶段:系统大部分时间都会处于运行态,运行态最重要的是对系统的监控要准确及时,发现问题能够准确报警并且报警数据要准确详细,以便于排查问题。

 为什么系统的高可用建设要放到整个生命周期中全面考虑?因为我们在每个环节中都可能犯错, 而有些环节犯的错是无法弥补的。例如在架构阶段,没有消除单点问题,那么系统 上线后,遇到突发流量把单点给挂了,加机器都加不进去。

那么针对秒杀系统,我们重点介绍在遇到大流量时,应该从哪些方面来保障系统的稳定运行,所 以更多的是看如何针对运行阶段进行处理,这就引出了接下来的内容:降级、限流

降级:就是当系统的容量达到一定程度时,限制或者关闭系统的某些非核心功能,从而把有限的资源保留给更核心的业务。降级方案可以这样设计:当秒杀流量达到5w/s时,把成交记录的获取从展示20条降级到只展示5条。 

执行降级无疑是在系统性能和用户体验之间选择了前者,降级后肯定会影响一部分用户的体验,。 所以降级的核心目标是牺牲次要的功能和用户体验来保证核心业务流程的稳定,是一个不得已而 为之的举措。

限流: 如果说降级是牺牲了一部分次要的功能和用户的体验效果,那么限流就是更极端的一种保护措施 了。限流就是当系统容量达到瓶颈时,我们需要通过限制一部分流量来保护系统,并做到既可以人工执行开关,也支持自动化保护的措施。

首先,来分别说下客户端限流和服务端限流的优缺点。 客户端限流,好处可以限制请求的发出,通过减少发出无用请求从而减少对系统的消耗,缺点 就是当客户端比较分散时,没法设置合理的限流阈值。如果阈值设的太小,会导致服务端没有 达到瓶颈时客户端已经被限制;而如果设的太大,则起不到限制的作用。 服务端限流,好处是可以根据服务端的性能设置合理的阈值,而缺点就是被限制的请求都是无效的请求,处理这些无效的请求本身也会消耗服务器资源。

以上的内容就是我所介绍的秒杀系统设计中的难点和一些解决思路,不是每个方案都完美,选择一个适合自己的才重要。