欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

秒杀系统架构设计

程序员文章站 2022-03-03 14:35:12
...
“秒杀”,就是在同一个时刻有大量请求争抢购买同一个商品,并完成交易的过程,其间涉及大量的并发读和并发写,并要求高可靠和高性能的系统支持。

关键词:稳、准、快。

要求:高性能,一致性,高可用。

高性能:秒杀涉及大量的并发读和写,需要支持高并发,数据动静分离,热点的发现与隔离,请求的削峰与分层过滤、服务端的优化

一致性:商品库存需要一致性,不可超卖或少卖,保证数据的准确性。

高可用:做兜底方案,一但系统故障,不影响系统使用。






架构原则:

1、数据要尽量少

2、请求数要尽量少

3、路径要尽量短

4、依赖要尽量少

5、不要单机系统

一、动静分离

把用户请求的数据划分为动态数据和静态数据。

静态数据做缓存,常见的有浏览器,CDN,服务端Cache。

静态化改造就是要直接缓存HTTP连接。

改造内容:

1、URL唯一化。为啥要URL唯一呢?缓存整个HTTP连接,就可以用URL作为缓存的Key。

2、分离浏览者相关的因素。浏览者相关的因素包括是否已登录,以及登录身份等,这些相关因素我们可以单独拆分出来,通过动态请求来获取。

3、分离时间因素。服务端输出的时间也通过动态请求获取。

4、异步化地域因素。详情页面上与地域相关的因素做成异步方式获取,当然你也可以通过动态请求方式获取,只是这里通过异步获取更合适。

5、去掉Cookie。服务端输出的页面包含的Cookie可以通过代码软件来删除,如Web服务器Varnish可以通过unset req.http.cookie 命令去掉Cookie。注意,这里说的去掉Cookie并不是用户端收到的页面就不含Cookie了,而是说,在缓存的静态数据中不含有Cookie。

改造方案:


1、ESI方案(或者SSI):即在Web代理服务器上做动态内容请求,并将请求插入到静态页面中,当用户拿到页面时已经是一个完整的页面了。这种方式对服务端性能有些影响,但是用户体验较好。

2、CSI方案。即单独发起一个异步JavaScript 请求,以向服务端获取动态内容。这种方式服务端性能更佳,但是用户端页面可能会延时,体验稍差。

动静分离3种架构方案:

(1)实体机单机部署

1、没有网络瓶颈,能使用大内存

2、能提升命中率,减少Gzip压缩

3、减少Cache失效压力

4、hash 分组越少,缓存的命中率肯定就会越高,但短板是也会使单个商品集中在一个分组中,容易导致 Cache 被击穿,所以我们应该适当增加多个相同的分组,来平衡访问热点和命中率的问题

(2)统一Cache层

优点:

1、减少运维成本,方便接入其他静态化系统

2、可以共享内存

缺点:

1、Cache层内部交换网络成为瓶颈

2、缓存服务器网卡瓶颈

3、风险较大




(3)CDN

1、失效问题,CDN上可以主动失效,存储在浏览器不可控,只有用户主动刷新才可以失效。

2、命中率问题

3、发布更新问题

CDN部署有以下几个特点:

1、整个页面缓存在用户浏览器中

2、强制刷新整个页面,也会请求CDN

3、实际有效请求,只是用户对按钮的点击



二、实时热点发现与处理

1、发现热点数据

发现静态热点数据与动态数据

静态数据方式:

1、提前报名筛选

2、TOPN商品

动态数据方式:

1、构建一个异步的系统,它可以收集交易链路上各个环节中的中间件产品的热点Key,如Nginx、缓存、RPC服务框架等这些中间件(一些中间件产品本身已经有热点统计模块)。

2、建立一个热点上报和可以按照需求订阅的热点服务的下发规范,主要目的是通过交易链路上各个系统(包括详情、购物车、交易、优惠、库存、物流等)访问的时间差,把上游已经发现的热点透传给下游系统,提前做好保护。比如,对于大促高峰期,详情系统是最早知道的,在统一接入层上Nginx模块统计的热点URL。

3、将上游系统收集的热点数据发送到热点服务台,然后下游系统(如交易系统)就会知道哪些商品会被频繁调用,然后做热点保护。



2、处理热点数据

(1)优化

优化热点数据最有效的办法就是缓存热点数据,如果热点数据做了动静分离,那么可以长期缓存静态数据。但是,缓存热点数据更多的是“临时”缓存,即不管是静态数据还是动态数据,都用一个队列短暂地缓存数秒钟,由于队列长度有限,可以采用LRU淘汰算法替换。
(2)限制

限制更多的是一种保护机制,限制的办法也有很多,例如对被访问商品的ID做一致性Hash,然后根据Hash做分桶,每个分桶设置一个处理队列,这样可以把热点商品限制在一个请求队列里,防止因某些热点商品占用太多的服务器资源,而使其他请求始终得不到服务器的处理资源。
(3)隔离

1、业务隔离(域名)

2、系统应用隔离

3、数据隔离




三、削峰

削峰的3种处理方式:

一个是通过队列来缓冲请求,即控制请求的发出;

一个是通过答题来延长请求发出的时间,在请求发出后承接请求时进行控制,最后再对不符合条件的请求进行过滤;

最后一种是对请求进行分层过滤。

1、排队

通过引入消息队列(MQ),将请求放入队列中,通过队列先进先出的特点,来达到削峰。

队列选型:大型选火箭(RocketMQ),中小型选兔子(RabbitMQ)。







2、答题

目的:

1、防止部分买家使用秒杀器在参加秒杀时使用。

2、延缓请求,起到对请求流量进行削峰的作用,从而让系统能够更好地支持瞬时的流量高峰。





加入答题环节,需要引入题库系统:

1、题库生成模块

2、题库的推送模块

3、题目的图片生成模块,用于把题目生成为图片格式,并且在图片里增加一些干扰因素。

3、分层过滤(漏斗式)

大部分数据和流量在用户浏览器或者CDN上获取,这一层可以拦截大部分数据的读取;

经过第二层(即前台系统)时数据(包括强一致性的数据)尽量走Cache,过滤一些无效的请求;

再到第三层后台系统,主要做数据的二次检验,对系统做好保护和限流,这样数据量和请求就进一步减少;

最后在数据层完成数据的强一致性校验。

分层校验的基本原则是:

将动态请求的读数据缓存(Cache)在Web端,过滤掉无效的数据读

对读数据不做强一致性校验,减少因为一致性校验产生瓶颈的问题

对写数据进行基于时间的合理分片,过滤掉过期的失效请求

对写请求做限流保护,将超出系统承载能力的请求过滤掉

对写数据进行强一致性校验,只保留最后有效的数据

分层校验的目的:对读系统,尽量减少由于一致性校验带来的系统瓶颈,尽量将不影响性能的检查条件提前;对写系统对写数据做一致性检查,在数据库层保证数据的最终准确性。



四、扣减库存核心逻辑

1、下单减库存,即当买家下单后,在商品的总库存中减去买家购买数量。下单减库存是最简单的减库存方式,也是控制最精确的一种,下单时直接通过数据库的事务机制控制商品库存,这样一定不会出现超卖的情况。但是你要知道,有些人下完单可能并不会付款。

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

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

针对秒杀场景,采用下单减库存,针对秒杀场景,下单成功不付款几乎不存在;其他的电商一般采用预留库存的方式。

五、系统可用性保障

所谓兜底保护就是上线后,系统一旦出现故障,需要怎么应急处理,既然出现故障,当然就会体验不好的,但是为了活动,还得把任务完成。

1、服务降级

2、限流

3、拒绝服务



老王推荐阅读:

1、《深入分析Java Web技术内幕》。

2、《架构演进与性能优化》。

https://mp.weixin.qq.com/s/gnW5Yom6Vf7Wii2kCN1qKQ
相关标签: 框架 活动