一、秒杀中的减库存
减库存操作一般有如下几个方式:
1.下单减库存:下单后,在商品的总库存中减去购买数量,下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。
2.付款减库存:下单后,并不立即减库存,而是等到付款后才真正减库存,否则库存一直保留给其他买家,但因为付款时才减库存,如果并发比较高,有可能出现买家下单后付不了款的情况,可能商品已经被其他人买走了。
3.预扣库存:下单后,库存为其保留一定的时间, 超过这个时间,库存将会自动释放,释放后其他买家就可以继续购买,在买家付款前,系统会校验该库存是否还有保留,如果没有保留,则再次尝试预扣;如果库存不足则不允许继续付款;如果预扣成功,则完成付款并实际地减去库存,这种方式相对复杂一些。
以上这几种减库存的方式都会存在一些问题。 假如我们采用“下单减库存”的方式,正常情况下,买家下单后付款的概率会很高,所以不会有太大问题,但是有一种场景例外,就是当卖家参加某个活动时,此时活动的有效时间是商品的黄金售卖时间,通过恶意下单的方式将该卖家的商品全部下单,那么这款商品就不能正常售卖了。要知道,这些恶意下单的人是不会真正付款的。
既然“下单减库存”和“付款减库存”都有缺点,我们能否采用“预扣库存”这种方式呢? 这种方案确实可以在一定程度上缓解上面的问题,但是否就彻底解决了呢?针对恶意 下单这种情况,虽然把有效的付款时间设置为10分钟,但是恶意买家完全可以在10分钟后再次下单。
由于参加秒杀的商品成功下单后却不付款的情况比较少,再加上卖家对秒杀商品的库存有严格限制,所以秒杀商品采用“下单减库存”更加合理。一般我们有多种解决方案:一种是在应用程序中通过事务来判断,即保证减后库存不能为负数,否则就回滚;另一种办法是直接设置数据库的字段数据为 无符号整数, 这样减后库存字段值小于零时会直接执行SQL语句来报错。
二、秒杀中的高可用
1.架构阶段:架构阶段主要考虑系统的可扩展性和容错性,要避免系统出现单点问题,例如多机房部署,即使某个机房出现整体故障,仍然不会影响整体网站的运转。
2.编码阶段:编码最重要的是保证代码的健壮性,例如涉及远程调用问题时,要设置合理的超时退出机制,防止被其他系统拖垮。
3.测试阶段:测试主要是保证测试用例的覆盖度,保证最坏情况发生时,我们也有相应的处理流 程。
4.运行阶段:系统大部分时间都会处于运行态,运行态最重要的是对系统的监控要准确及时,发现问题能够准确报警并且报警数据要准确详细,以便于排查问题。
那么针对秒杀系统,我们重点介绍在遇到大流量时,应该从哪些方面来保障系统的稳定运行,所 以更多的是看如何针对运行阶段进行处理,这就引出了接下来的内容:降级、限流。
降级:就是当系统的容量达到一定程度时,限制或者关闭系统的某些非核心功能,从而把有限的资源保留给更核心的业务。降级方案可以这样设计:当秒杀流量达到5w/s时,把成交记录的获取从展示20条降级到只展示5条。
限流: 如果说降级是牺牲了一部分次要的功能和用户的体验效果,那么限流就是更极端的一种保护措施 了。限流就是当系统容量达到瓶颈时,我们需要通过限制一部分流量来保护系统,并做到既可以人工执行开关,也支持自动化保护的措施。
客户端限流,好处可以限制请求的发出,通过减少发出无用请求从而减少对系统的消耗,缺点 就是当客户端比较分散时,没法设置合理的限流阈值。如果阈值设的太小,会导致服务端没有 达到瓶颈时客户端已经被限制;而如果设的太大,则起不到限制的作用。 服务端限流,好处是可以根据服务端的性能设置合理的阈值,而缺点就是被限制的请求都是无效的请求,处理这些无效的请求本身也会消耗服务器资源。
以上的内容就是我所介绍的秒杀系统设计中的难点和一些解决思路,不是每个方案都完美,选择一个适合自己的才重要。