秒杀系统架构设计
这是许令波老师在极客时间发起的课程,以下是我的学习笔记。
早期淘宝秒杀活动的PV(访问量)差不多1亿,2016年就有50亿了,系统要面对的流量成倍增长。
秒杀主要解决两个问题:并发读,并发写。
要想打造并维护一个超大流量并发读写、高性能、高可用的系统,在整个用户请求路径上从浏览器到服务端我们要遵循几个原则,就是要保证用户请求的数据尽量少、请求数尽量少、路径尽量短、依赖尽量少,并且不要有单点。
秒杀的整体架构可以概括为“稳、准、快”几个关键字。
“稳”,就是整个系统架构要满足高可用,流量符合预期时肯定要稳定,就是超出预期时也同样不能掉链子,你要保证秒杀活动顺利完成,即秒杀商品顺利地卖出去,这个是最基本的前提。
“准”,就是秒杀 10 台 iPhone,那就只能成交 10 台,多一台少一台都不行。一旦库存不对,那平台就要承担损失,所以“准”就是要求保证数据的一致性。
“快”,很好理解,它就是说系统的性能要足够高,否则你怎么支撑这么大的流量呢?不光是服务端要做极致的性能优化,而且在整个请求链路上都要做协同的优化,每个地方快一点,整个系统就完美了。
所以从技术角度上看“稳、准、快”,就对应了我们架构上的高可用、一致性和高性能的要求。
高性能。 秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。将从设计数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这 4 个方面重点介绍。
一致性。 秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知。因此,我将用一篇文章来专门讲解如何设计秒杀减库存方案。
高可用。 虽然介绍了很多极致的优化思路,但现实中总难免出现一些我们考虑不到的情况,所以要保证系统的高可用和正确性,我们还要设计一个 PlanB 来兜底,以便在最坏情况发生时仍然能够从容应对。
1.秒杀系统的5个架构原则
秒杀系统本质上就是一个满足大并发、高性能和高可用的分布式系统。
架构原则:“4要 1不要”
- 数据要尽量少:减少CPU使用(简化页面大小,去掉多余装饰)
指用户请求的数据能少就少。请求的数据包括上传给系统的数据和系统返回给用户的数据(通常就是网页)。和数据库打交道越少越好,数据越简单、越小则越好。 - 请求数要尽量少:这个页面依赖的 CSS/JavaScript、图片,以及 Ajax 请求等“额外请求”应该尽量少。
- 路径尽量短:用户发出请求到返回数据这个过程中,需求经过的中间的节点数。增加可用性,有效提升性能(减少中间节点可以减少数据的序列化与反序列化),并减少延时(可以减少网络传输耗时)。办法:多个相互强依赖的应用合并部署在一起,把远程过程调用(RPC)变成 JVM 内部之间的方法调用。
- 依赖尽量少:完成一次用户请求必须依赖的系统或者服务,这里的依赖指的是强依赖。
举例,要展示秒杀页面,这个页面必须强依赖商品信息、用户信息,还有其他如优惠券、成交列表等这些对秒杀不是非要不可的信息(弱依赖),这些弱依赖在紧急情况下就可以去掉。 - 不要有单点。避免将服务的状态和机器绑定,即把服务无状态化,这样服务就可以在机器中随意移动。
快速搭建简单的秒杀系统,只需把商品购买页面增加一个“定时上架”功能,仅在秒杀开始时才让用户看到购买按钮,当商品的库存卖完了也就结束了。这就是当时第一个版本的秒杀系统实现方式。
请求量的加大(比如从 1w/s 到了 10w/s 的量级),这个简单的架构很快就遇到了瓶颈,改造包括:
1.把秒杀系统独立出来单独打造一个系统,有针对性地做优化,例如这个独立出来的系统就减少了店铺装修的功能,减少了页面的复杂度;
2.在系统部署上也独立做一个机器集群,这样秒杀的大流量就不会影响到正常的商品购买集群的机器负载;
3.将热点数据(如库存数据)单独放到一个缓存系统中,以提高“读性能”;
4.增加秒杀答题,防止有秒杀器抢单。
这个架构仍然支持不了超过 100w/s 的请求量,改进:
1.对页面进行彻底的动静分离,使得用户秒杀时不需要刷新整个页面,而只需要点击抢宝按钮,借此把页面刷新的数据降到最少;
2.在服务端对秒杀商品进行本地缓存,不需要再调用依赖系统的后台服务获取数据,甚至不需要去公共的缓存集群中查询数据,这样不仅可以减少系统调用,而且能够避免压垮公共缓存集群。
3.增加系统限流保护,防止最坏情况发生。
2. 数据的动静分离
所谓“动静分离”,其实就是把用户请求的数据(如 HTML 页面)划分为“动态数据”和“静态数据”。
“动态数据”和“静态数据”的主要区别就是看页面中输出的数据是否和 URL、浏览者、时间、地域相关,以及是否含有 Cookie 等私密数据。
对静态数据做缓存:
1.缓存到离用户最近的地方
2.静态化改造就是要直接缓存 HTTP 连接
动态页面改造成适合缓存的静态页面:
1.URL 唯一化
2.分离浏览者相关的因素
3.分离时间因素
4.异步化地域因素
5.去掉Cookie
动态内容的处理通常有两种方案:ESI(Edge Side Includes)方案和 CSI(Client Side Include)方案。
1.ESI 方案(或者 SSI):即在 Web 代理服务器上做动态内容请求,并将请求插入到静态页面中,当用户拿到页面时已经是一个完整的页面了。这种方式对服务端性能有些影响,但是用户体验较好。
2.CSI 方案。即单独发起一个异步 JavaScript 请求,以向服务端获取动态内容。这种方式服务端性能更佳,但是用户端页面可能会延时,体验稍差。
动静分离的几种架构方案
1.实体机单机部署;
2.统一 Cache 层;
3.上 CDN。