秒杀系统瞬时百万并发流量的六种应对之道(十年高并发大促经验总结)
作者:冰河
星球:http://m6z.cn/6aeFbs
博客:https://binghe.gitcode.host
文章汇总:https://binghe.gitcode.host/md/all/all.html
源码获取地址:https://t.zsxq.com/0dhvFs5oR
备注:本文节选自 冰河技术 知识星球《Seckill秒杀系统》专栏
沉淀,成长,突破,帮助他人,成就自我。
- 本章难度:★★★☆☆
- 本章重点:全面阐述建设秒杀系统挑战的应对之道,知己知彼,方案了然于胸,自然有应对之道。经过长期秒杀大促的沉淀与总结,针对秒杀系统存在高并发大流量的挑战,冰河沉淀出六种应对之道:分离、限流、快速响应、准确一致、稳定可靠、全链路压测。
大家好,我是冰河~~
虽然建设秒杀系统的过程中存在着诸多的挑战,但是这些挑战都是有应对之道的,对于整个过程中遇到的难点和痛点,都是会沉淀出对应的解决方案。
一、前言
在前面的文章中,详细阐述了建设秒杀系统的目标与存在的挑战,并且简单罗列了如何应对这些挑战的方式。本章,就详细阐述对秒杀系统存在挑战的应对之道,最终构建出兼具高并发、高性能和高可用的秒杀系统。心中不仅了解建设秒杀系统存在的挑战,更清楚的知道这些挑战的应对之道,正所谓:知己知彼,百战不殆,方案了然于胸,自然有应对之法。
二、本章诉求
一般一套成熟并且稳定、经得起实际大促场景考验的秒杀系统,都是经过不断迭代、优化和演化而来的。对于设计和研发秒杀系统的技术人员来说,心中一定要清晰的知晓建设秒杀系统存在的挑战,以及针对这些挑战的应对之法。
三、应对之道
对于秒杀系统,站在技术人员的角度,相信大家多多少少对秒杀系统有所了解了。既然建设秒杀系统存在着种种的困难和挑战,那我们就需要从整体上分析这些挑战的应对之法,而不是在真正开发秒杀系统时,再去临时想方案,查漏补缺,切忌头痛医头、脚痛医脚。
从总体上说,我们应对秒杀系统挑战时,心中要有一杆秤,在设计秒杀系统时,一定要做到分离、削峰限流、快速响应、准确一致、稳定可靠、全链路压测。
接下来,就针对每种应对之道进行详细的阐述。
四、分离之道
分离之道中,重点在于一个“分”字,主要包括:前后端资源分离、接口分离,数据分离、业务分离、系统分离、流量分离。
4.1 资源分离
资源分离,主要指的是前后端的资源分离。目前,除了一些非常老旧的系统之外,一般在开发互联网项目过程中,都会采用前后端分离的架构模式,这也是比较普遍的做法。在秒杀系统中,将前端资源分离出来,部署时可以直接推送到CDN服务器,CDN服务器全国各地都有,用户在访问系统时,可以从就近的CDN服务器上拉取对应的资源,能够极大的增强系统的性能。
4.2 接口分离
接口分离包含两个方面:一个是秒杀接口与其他接口分离,一个是高频访问接口与低频访问接口分离。
对于秒杀系统的接口来说,在设计上一定要与其他的接口进行分离,不要让秒杀系统的接口与其他业务的接口互相关联引用,避免秒杀系统的瞬时高并发流量对其他接口造成影响。
就秒杀系统而言,并不是每个接口的访问频次都一样,一本情况下,商品详情页、结算页和秒杀下单接口的访问频次要远远大于支付接口的访问频次。在设计上一定要将这些接口进行区分隔离,对高频访问的接口进行单独的性能优化。
4.3 数据分离
数据分离也会包含两个方面:一个是秒杀数据与其他数据分离,一个是动态数据与静态数据分离。
一般情况下,秒杀数据瞬时的增长率会远远大于其他数据,在数据上进行分离,可以对秒杀数据的存储设施进行单独的针对性优化,不能让秒杀数据对其他数据产生影响,在数据层面对秒杀系统进行专有部署。
就秒杀系统而言,本身也会存在着动态数据和静态数据。动态数据在秒杀期间会容易发生变更,比如秒杀系统的品类、商品的库存和上下架的状态等,都是的动态数据,这些动态数据对时间比较敏感。而像秒杀结果等与用户本身相关的一些数据,可以称为静态数据,因为这些数据在整个秒杀活动期间,基本不会发生变化。
在设计上,需要对这些动态数据和静态数据进行分离,因为数据的更新频率不同,在优化手段和架构设计上也会存在着差异。对动态数据和静态数据进行分离后,也可以将服务端产生的静态数据推送到CDN。
4.4 业务分离
秒杀业务不同于普通的商城业务,秒杀业务的特点就是流量大、持续的时间短,在设计秒杀系统时,需要充分考虑到不同业务之间的影响,做到秒杀业务与其他业务之间的分离。
4.5 系统分离
秒杀系统与其他系统不同,秒杀系统需要承接瞬时高并发流量,而其他大部分系统的流量则比较平缓。一旦将秒杀系统和其他业务系统部署到一起的话,势必会对其他业务系统造成比较大的影响,所以,需要将秒杀系统与其他业务系统进行分离处理。
在系统分离层面,一般在大厂的秒杀系统中会将秒杀详情页系统、秒杀结算页系统、购物车系统和订单系统进行分离,并且会申请单独的域名和负载均衡器等,并且会对相应的微服务集群进行分组隔离。
4.6 流量分离
看到这里,相信大家对秒杀系统的印象更加深刻了。没错,秒杀系统的瞬时流量是巨大的,如果秒杀系统的流量与其他业务系统的流量不加以分离处理,其他系统势必会由于巨大的瞬时流量而导致各种连锁问题,所以,在设计上,务必将秒杀系统与其他业务系统的流量进行分离。
五、限流之道
限流主要是对流量进行限制,对于秒杀这种业务场景来说,流量是瞬时且巨大的,期间流量会在几秒钟之内爬升到峰值,然后马上又掉下来,形成巨大的毛刺峰值,对系统费资源的消耗也是瞬时且巨大的,需要对这些流量进行限制和管控。通常的应对方法主要有:提前预约秒杀、打散客户端流量、消息队列、网关限流、API限流、应用层限流、安全校验、活动校验,秒杀商品校验、秒杀资格校验、风控校验,大厂策略。
5.1 提前预约秒杀
为秒杀系统设计一个预约功能,或者单独设计一个预约系统,用户要想参与秒杀抢购,则需要提前预约商品的抢购,这样可以在参与抢购的用户基数上进行控制,能够提前锁定参与秒杀抢购的用户,而不是整个平台中所有的用户都能参与抢购。这样可以通过将抢购的用户访问控制在预约人数之内,在一定程度上能够大大减少秒杀的峰值流量,对秒杀系统起到一定的防护作用。
5.2 打散客户端流量
一般秒杀系统的客户端也会包含:PC、H5、App和小程序,作为秒杀流量的入口,可以在这些入口端设置答题、验证码和滑块等方式将流量打散,因为每个人输入问答题答案、验证码和滑块的手速不同,就会将瞬时的大并发流量分散到一小段时间内。在秒杀的场景中,不要小看这些处理方式,即使将流量分摊到一秒或者几百毫秒的时间内,也会将流量峰值降低一个甚至几个量级。
例如,在没有将客户端浏览打散的情况下,流量峰值为100万QPS,使用答题、验证码和滑块的方式将流量打散后,流量峰值可能就会下降到80万QPS、60万QPS甚至更低,对秒杀系统能过起到有效的防护作用。
另外,使用问答题、验证码和滑块的方式也能够快速拦截部分刷单流量、防止机器作弊,起到一定的防刷作用。
注意:目前像阿里这样的头部电商平台,已经不会在客户端使用问答题、验证码和滑块等方式将流量打散,更倾向于采用非公平的策略,使用有损逐级限流和分层过滤的方式来达到系统限流的目的。
5.3 消息队列
使用消息队列来削峰填谷,通过消息队列可以将同步的请求改造成异步请求,将超过下游系统处理范围的流量暂时存入消息队列中,下游的系统可以根据自身处理数据的性能来消费队列中的数据。
使用消息队列对抢购下单异步化之后,前端不能及时知晓秒杀的结果数据,需要前端定期查询秒杀的结果数据反馈给用户。在使用消息队列设计异步抢购流程时,有个小技巧:就是前面的请求将商品的库存消耗完之后,在商品库存的缓存中设置一个特殊占位符,让后续的请求能够快速失败,而不再进行后续的业务逻辑处理。
可以使用RocketMQ、Kafka和RabbitMQ等消息中间件来实现请求的异步化和削峰填空,具体使用哪种消息中间件可以根据自身业务进行实际评估。
5.4 网关限流
网关一般是一个系统的入口,可以在网关层对流量进行限流,对超出当前系统流量阈值的请求根据一定的策略进行处理,例如拒绝超出当前系统流量阈值的请求,快速返回失败,也可以将超出阈值的流量缓存起来进行排队,按照一定的顺序消费这些请求,会对下游的业务系统起到一定的防护作用。
5.5 API限流
API限流也就是对接口进行限流,可以使用Google提供的RateLimiter开源包,实现对应的限流策略,在系统中具体的API代码里进行限流。这种方式可以做到针对特定的API接口进行限流。
5.6 应用层限流
应用层的限流可以通过对线程池的限流来实现,实现线程池的限流时,主要是设置并发数限流,可以通过自定义线程池,配置最大的连接数,以请求队列的长度和拒绝策略等参数进行限流,如果队列已满,并且已经达到最大的线程数,多余的请求就会根据具体的拒绝策略进行处理,以达到限流的目的和效果。
5.7 安全校验
安全校验就是要识别出请求的流量哪些是安全流量,哪些是不安全的流量,这里说的不安全的流量指的是友商、黄牛党或者不怀好意的用户发起的刷单流量、CC攻击等,这种流量对系统是有害的,能够消耗大量的系统资源,为系统造成比较大的压力,并且这种方式挤占了正常抢购的通道,对正常参与秒杀活动的用户是不公平的。
5.8 活动校验
活动校验就是接收到请求时,对活动数据进行校验,核对活动是否已经结束、是否下架等等,如果活动已经结束或者已经下架,则在缓存中设置特殊的占位符,对后续的请求进行快速失败处理,不再进行后续的逻辑处理。
做活动校验的原因是用户在客户端看到活动有效,当流量达到服务端时,活动可能已经结束或者失效了,所以需要做活动的校验处理。
5.9 秒杀品校验
秒杀品校验就是在接收到请求时,对当前的商品信息进行校验,核对当前商品是否有效,库存是否充足等。如果商品不再有效、或者库存已经消耗完毕,则在缓存中设置特殊的占位符,对后续的请求进行快速失败处理,不再进行后续的逻辑处理。
做秒杀品校验的原因是用户在客户端看到活动有效,当流量达到服务端时,秒杀品可能已经结束或者失效了,所以需要做秒杀品的校验处理。
5.10 秒杀资格校验
秒杀资格校验主要是对参与秒杀的用户的资格进行校验,比如设计了预约环节时,只有提前预约过秒杀抢购的用户才能参与秒杀。再比如,针对当前活动设置了只能秒杀一次的用户,如果当前用户存在本次活动的秒杀记录,就不再允许二次秒杀等等。还有就是如果对秒杀品设置了只针对某些地区开放秒杀活动,则需要判断用户的所在地是否在开放的地区,如果不在开放秒杀的地区,则不允许抢购等等。
另外,在秒杀的资格校验上,可能存在同一个用户不断伪造请求的现象,需要加强用户唯一身份的校验等逻辑。
5.11 风控校验
一个成熟稳定的秒杀系统的背后会接入风控系统,对整个秒杀活动进行风控处理,风控系统的建设不是一朝一夕就能完成的,建立风控的过程也是比较困难的,这需要建立在大量数据的基础之上,不断的完善用户的画像,需要通过复杂的业务场景的考验,不断的修正风控模型。
5.12 大厂策略
像阿里这种头部互联网公司,其秒杀系统处了会使用上述限流之道进行系统限流外,其处于兼顾用户体验和系统资源的考虑,一般不会采用问答题、验证码或者滑块的方式来打散客户端流量,更倾向于采用非公平的策略,使用有损逐级限流和分层过滤的方式来达到系统限流的目的。
六、快速响应之道
秒杀的场景虽然是高并发、大流量的业务场景,但是在秒杀场景中,需要快速响应用户的请求,不能让用户出现长时间等待的情况,这就需要在秒杀系统的设计上采用一定的策略。对于快速响应来说,可以从多用缓存、本地缓存、分布式缓存、数据尽量少、计算尽量少和流程尽量简单几个方面进行设计。
6.1 多用缓存
像秒杀这种在高并发大流量场景下要求极致体验的系统,缓存是必不可少的,无论是对前端资源还是对后端数据来说,使用缓存都能够极大的提升系统的性能。同时,使用缓存也能够对系统进行一定的防护。
如果系统中没有使用缓存,或者发生了缓存穿透或者雪崩,瞬时的大量请求直接打到数据库,那数据库连接会被瞬间耗尽而导致不可用,进而导致严重的连锁反应,整个系统都会被拖垮,所以,使用缓存是非常重要的。
6.2 本地缓存
在秒杀系统中,为了进一步提升系统的性能,会将一部分非常热点的数据缓存在本地的JVM内存中,接收到请求后,会先从本地缓存中获取数据,如果本地缓存不存在要获取的数据,就会到分布式缓存中进行查询。
6.3 分布式缓存
除了本地缓存外,分布式缓存也是秒杀系统必不可少的,本地缓存的数据有限,只能缓存一部分极度热点的数据,并且这些极度热点的数据开始在本地缓存中也不一定存在,这就需要分布式缓存的存在,如果本地缓存中没有数据,就到分布式缓存查询,尽最大努力提升系统的性能。
6.4 数据尽量少
对于提升系统的响应性能来说,光有缓存还不够,还要在处理的数据上要尽量少,不要查询或者返回无关紧要的数据。因为缓存只是提升了IO的执行效率,但是除了要提升IO的执行效率,还要提升数据在网络中的传输效率、以及内存和磁盘的读写效率。这些都要求我们处理的数据要尽量少。
6.5 计算尽量少
除了数据尽量少以外,对于数据的计算操作也要尽量少,尽量不涉及复杂的计算操作,复杂的计算操作会消耗大量的CPU资源,会极大的影响系统的响应性能。
6.6 流程尽量简单
秒杀系统在流程设计中要尽量简单,不要涉及到复杂的业务流程,流程越简单,处理的业务逻辑越少,性能就越高效。
七、准确一致之道
缓存是秒杀系统必不可少的,但是使用缓存之后,就会出现数据一致性的问题,这些数据一致性的问题,就是需要考虑和处理的,主要包含:缓存与数据库一致、本地缓存与分布式缓存一致、商品库存与订单数据一致、前端与后端数据一致。
7.1 缓存与数据库一致
使用缓存能够极大的提升系统的性能,但是使用了缓存之后,需要在确保缓存中的数据和数据库中的数据是一致的。这种一致性需要根据场景决定是强一致性还是弱一致性,亦或是最终一致性。
7.2 本地缓存与分布式缓存一致
本地缓存和分布式缓存都能够提升数据的性能,对于极度热点数据来说,最好是存储在本地缓存中来提升系统的性能,但是这就需要考虑本地缓存与分布式缓存数据的一致性问题。
7.3 商品库存与订单一致
这里说的商品库存与订单一致,指的是商品已经消耗的库存数量与订单中的商品数量一致,不能出现超卖问题,这就需要在秒杀系统的设计中,充分考虑到商品库存的扣减问题。
7.4 前端与后端数据一致
前端与后端的数据一致,指的是在秒杀过程中尽量做到前端的数据与后端的数据保持一致,这里说的一致,就不是强一致了,而是最终一致。因为参与秒杀的用户很多,可能会出现某个用户在客户端看到的商品库存剩余100件,发起秒杀抢购的请求后,请求发送到服务端,服务端检测到商品库存已经耗光,就会返回库存不足或者秒杀已结束的提示,这种场景就可以归类为最终一致。
八、稳定可靠之道
一个系统的稳定性是重中之重要考虑的问题,一个秒杀系统必须要具备高度的稳定性,要想满足系统的稳定性,可以从隔离策略和监控的角度来保证系统的稳定性。隔离可以从业务隔离、系统隔离和数据隔离的角度进行考虑,监控就可以从监控数据库与基础指标、JVM指标和中间件等指标的角度进行考虑。
8.1 业务隔离
秒杀系统在业务上与其他系统进行隔离,对于参与秒杀的商品来说,一般会在秒杀活动开始前,提前进行提报,并且指定详细的营销策划和方案。对于参与用户来说,提前预约,可以提前识别流量和系统的并发数,根据具体情况评估是否需要扩容、是否需要降级或者调整限流策略。
8.2 系统隔离
对于被流量冲击比较大的核心系统进行物理隔离,链路末端的系统,经过前面的削峰限流之后,流量就比较可控了,可以不做物理隔离,在逻辑上进行隔离即可。在大厂中,一般会将秒杀的商详页系统、秒杀结算页系统、购物车系统和订单系统单独隔离出来。
8.3 数据隔离
对于秒杀系统的数据服务,例如Redis集群、MySQL集群等要单独隔离部署,做到秒杀数据与其他业务数据的隔离。
除此之外,还要将流量正确的路由到秒杀专有的环境中。
8.4 监控数据库与基础指标
除了通过隔离策略增强系统的稳定性之外,还要时刻关注系统的风险指标,对数据库、CPU使用率、内存使用率、负载、网卡、磁盘、IO、网络波动等进行监控。
8.5 监控JVM指标
监控JVM的指标可以包含:Young GC和Full GC的次数和耗时,线程池的线程数和等待队列,运行中的线程,死锁的线程,以及JVM的堆栈使用情况等等。
8.6 监控中间件指标
监控中间件的指标,一般情况下可以缓存的容量、QPS和RT进行监控,对于数据库的QPS、容量和连接池进行监控,对消息中间件的QPS、RT以及消息的堆积情况进行监控,对整个交易链路的分支系统进行监控等等。
九、全链路压测之道
对于秒杀这种系统高并发、大流量的系统来说,单一的测试功能和对交易链路上某一部分功能都不能测试出整个秒杀系统的性能瓶颈点,要知道木桶能不能装满水是取决于最短的木板,对于系统来说也是,整体性能也是取决于整个交易链路上性能最低的一环。所以,需要对秒杀系统进行全链路压测。根据实际压测出来的数据进行针对性的优化和调整。
十、总结
本章,主要是对秒杀系统高并发大流量的挑战给出了应对之道,从总体上说,我们应对秒杀系统挑战时,心中要有一杆秤,在设计秒杀系统时,一定要做到分离、削峰限流、快速响应、准确一致、稳定可靠、全链路压测。
最后,可以在评论区写下你学完本章节的收获,祝大家都能学有所成,我们一起搞定高并发秒杀系统。
文章转载自公众号:冰河技术