瞬时售空、限时、限量、限价、持续时间短、流量并发高
秒杀流量是占比比较重的一环,所以要独立部署,与其他业务分开,互不影响。扩容容易。
100个库存,1000个人购买,如何保证其中100个人能买到
主要是防止程序蹦掉。核心就是限制次数、限制总量、快速失败、降级运行
12306中选择购票时,选择自己靠窗座位时,所有下单请求,加入队列,满满匹配撮合。
使用各种手段、将流量分担到更大宽度的时间点、比如验证码、F码
秒杀读多写少(访问商品人数往往大于购买人数)。活动和库存都可以提前预热。比如把数据放到redis中。
nginx做好动静分离、使用CDN网络、分担后端的相应压力。
秒杀其实主要解决两个问题,一个是并发读,一个是并发写。
并发读的核心优化理念是尽量减少用户到服务端来"读′数据,或者让他们读更少的数据;
并发写的处理原则也一样,它要求我们在数据库层面独立出来一个库,做特殊的处理。另外,我们还要针对秒杀系统做一些保护,针对意料之外的情况设计兜底方案,以防止最坏的情况发生。
其实,秒杀的整体架构可以概括为“稳、准、快”几个关键字。
所谓稳就是整个网站要满足高可用,无论是流量多与少都能正确对外提供服务,可以保证让秒杀活动进行下去,不能掉链子。
所谓准就是一致性。我们知道在秒杀中商品数量是有限的,比如秒杀10台华为手机,那就只能成交10台,不能多卖也不能少卖。不能有损失,所以数量要准。
而这个数量其实就是我们扣减商品减库存数量,有限数量的商品在同一时刻被很多倍的请求同时来减库存。减库存又分为"拍下减库存""付款减库存"以及预扣等几种,
如果你第一次接触秒杀,那你可能还不太理解,库存100件就卖100件,在数据库里减到О就好了啊,这有什么麻烦的?是的,理论上是这样,但是具体到业务场景中,“威库存"就不是这么简单了。因为秒杀中并发是非常高的,在我们学习并发编程的时候也知道线程安全的问题,同样的在秒杀系统中对于扣减库存也会出现同样的问题,可能会出现库存超卖或者少卖的问题。
一般我们在电商平台上单,“立即购买"“提交订单”“支付成功”,那我们在哪一步进行扣减库存了?
即当买家下单后,在商品的总库存中减去买家购买数量。下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。但是你要知道,有些人下完单可能并不会付款。问题:有人恶意下单,下单之后不付款,霸占库存。
即买家下单后,并不立即减库存,而是等到有用户付款后才真正减库存,否则库存一直保留给其他买家。但因为付款时才减库存,如果并发比较高,有可能出现买家下单后付不了款的情况,因为可能商品已经被其他人买走了。
假如100件商品200个人抢,因为是付款才扣减库存,也就是200人都可以下单,当进行支付时100个人发现付不了款,因为被人已经付款成功,这种体验自然是比较差的。
这种方式相对复杂一些,买家下单后,库存为其保留一定的时间(如10分钟),超过这个时间,库存将会自动释放,释放后其他买家就可以继续购买。在买家付款前,系统会校验该订单的库存是否还有保留:如果没有保留,则再次尝试预扣;如果库存不足(也就是预扣失败)则不允许继续付款;如果预扣成功,则完成付款并实际地减去库存。
一般用QPS (Query Per Second,每秒请求数)来衡量一个网站的响应速度。QPS越高说明系统性能越好。那哪些点对QPS有影响了?
对于大部分的Web系统而言,响应时间一般都是由CPU执行时间和线程等待时间(比如RPC、Io等待、Sleep、Wait等)组成,即服务器在处理一个请求时,一部分是CPU本身在做运算,还有一部分是在各种等待。
那么针对秒杀系统,我们重点介绍在遇到大流量时,应该从哪些方面来保障系统的稳定运行,在运行阶段进行处理,系统需要考虑:降级、限流。
降级所谓°降级”,就是当系统的容量达到一定程度时,限制或者关闭系统的某些非核心功能,从而把有限的资源保留给更核心的业务。它是一个有目的、有计划的执行过程,所以对降级我们一般需要有一套预案来配合执行。
执行降级无疑是在系统性能和用户体验之间选择了前者,降级后肯定会影响一部分用户的体验,例如在双11零点时,下单的时候需要给用户增加积分,这个功能不是下单的核心功能,我们可以先记录一条信息,等后面流量下来之后在调用积分系统给用户补上积分
即保障用户真正下单和增加积分也不影响系统下单。所以降级的核心目标是牺牲次要的功能和用户体验来保证核心业务流程的稳定,是一个不得已而为之的举措。
如果说降级是牺牲了一部分次要的功能和用户的体验效果,那么限流就是更极端的一种保护措施了。限流就是当系统容量达到瓶颈时,我们需要通过限制一部分流量来保护系统,并做到既可以人工执行开关,也支持自动化保护的措施。这里,我同样给出了限流系统的示意图。总体来说,限流既可以是在客户端限流,也可以是在服务端限流。此外,限流的实现方式既要支持URL以及方法级别的限流,也要支持基于QPS和线程的限流。