3

秒杀系统架构设计

如何更好地理解秒杀系统

从高维度出发,从整体上思考问题。秒杀其实主要解决两个问题,一个是并发读,一个是并发写。

并发读的核心优化理念是尽量减少用户到服务端来读数据,或者让他们读更少的数据;

并发写的处理原则页一样,它要求我们在数据库层面独立出来一个库,做特殊的处理。

我们还要针对秒杀系统做一些保护,针对意料之外的情况设计兜底方案,以防止最坏的情况发生。

要打造并维护一个超大流量并发读写、高性能、高可用的系统,在整个用户请求路径上从浏览器到服务端我们要遵循几个原则,就是要保证用户请求的数据尽量少,请求数尽量少,路径尽量端,依赖尽量少,并且不要有单点。

秒杀的整体架构可以概括为"稳、准、快"几个关键字。

  • 稳,就是整个系统架构要满足高可用,流量符合预期时肯定要稳定,就是超出预期时也同样不能掉链子,你要保证秒杀活动顺利完成,即秒杀商品顺利地卖出去,这个时最基本地前提
  • 准,就是秒杀10台iPhone,那就只能成交10台,多一台少一台都不行。保证数据一致性。
  • 快,就是说系统地性能要足够高。不光是服务端要做极致地性能优化,而且在整个请求链路上都要做协同地优化,每个地方快一点,整个系统就完美了。

技术角度地看"稳、准、快",就对应了我们架构上地高可用、一致性和高性能地要求。

  • 高性能。秒杀涉及大量地并发读和并发写,因此支持高并发访问这个非常关键。从设计数据地动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这4各方面重点介绍。
  • 一致性。如何设计秒杀减库存方案
  • 高可用。从哪些环节来设计兜底方案

架构原则:"4要 1不要"

  1. 数据要尽量少

    首先是指用户请求的数据能少就少。因为这些数据传输需哟啊事件,服务器在写网络时要做压缩和字符编码,非常消耗CPU。其次,系统依赖的数据能少就少,包括系统完成某些业务逻辑需要读取和保存的数据,调用其他服务会设计数据的序列化和反序列化,会非常消耗cpu,与数据库打交道越少越好,数据越简单,越小则越好。

  2. 请求数要尽量少
  3. 路径要尽量短

    所谓"路径",就是用户发出请求到返回数据这个过程中,需求经过的中间节点数。通常,这些节点可以表示为一个系统或者一个新的socket链接。每经过一个几点,一般都会产生一个新的Socket链接。每增加一个链接都会增加新的不确定性。缩短请求路径不仅可以增加可用性,同样可以有效提升性能(减少数据的序列化与反序列化),并减少延时(可以减少网络传输耗时)。

    缩短访问路径有一种办法,就是多个相互强依赖的应用合并部署在一起,把远程过程调用变成JVM内部之间的方法调用。

  4. 依赖要尽量少

    所谓依赖,指的是要完成一次用户请求必须依赖的系统或者服务,这里的依赖指的是强依赖。

    举个例子,比如说你要是展示秒杀页面,而这个页面必须强依赖商品信息、用户信息,还有其他如优惠券、成交列表等这些对秒杀不是非要不可的信息(弱依赖),这些弱依赖在紧急情况下就可以去掉。

    要减少依赖,我们可以给系统进行分级,比如0级系统、1级系统、2级系统、3级系统,0级系统如果是最重要的系统,那么0级系统强依赖的系统也同样是最重要的系统,以此类推。

    注意,0级系统要尽量减少对1级系统的强依赖,防止重要的系统被不重要的系统拖垮。例如支付系统是0级系统,而优惠券是1级系统的话,在极端情况下可以把优惠券降级,防止支付系统被优惠券这个1级系统给拖垮。

  5. 不要有单点

    设计分布式系统最重要的原则就是"消除单点"。

    如何避免单点,我认为关键点是避免将服务的状态和机器绑定,即把服务无状态化,这样服务就可以在机器中随意移动。

不同场景下的不同架构案例

快速搭建简单的秒杀系统

商品购买页面增加一个"定时上架"功能,仅在秒杀开始时才让用户看到购买按钮,当商品的库存卖完了就结束了。

随着请求量的加大,这个简单的架构很快就遇到瓶颈。需要架构改造,包括:

  1. 把秒杀系统独立出来单独打造一个系统,这样可以有针对性地做优化。
  2. 系统部署上页独立做一个机器集群,这样秒杀大流量就不会影响到正常的商品购买集群的机器负载
  3. 将热点数据(如库存数据)单独放到一个缓存系统中,以提高"读性能"
  4. 增加秒杀答题,防止有秒杀器抢单。

改造后的系统架构

image.png

当访问量超百万的并发,需要进一步提升秒杀系统的性能,进一步升级,比如:

  1. 对页面进行彻底的动静分离,使得用户秒杀时不需要刷新整个页面,而只需要点击秒杀按钮,借此把页面刷新的数据降到最少;
  2. 在服务端对秒杀商品进行本地缓存,不需要再调用依赖系统的后台服务获取数据,甚至不需要去公共的缓存集群中查询数据,这样不仅可以减少系统调用,而且能够避免压垮公共缓存集群。
  3. 增加系统限流保护,防止最坏情况发生。

在这里,我们对页面进行了进一步的静态化,秒杀过程中不需要刷新整个页面,而只需要服务端请求很少的动态数据。而且,最关键的详情和交易系统都增加了本地缓存,来提前缓存秒杀商品的信息,热点数据库也做了独立部署,等等。

image.png

每次升级都需要定制很多地方,也就是越"不通用"。例如,秒杀商品缓存在每台机器的内存中,这种方式显然不太适合太多商品同时进行秒杀的情况,因为单机的内存始终有限。所以要取得极致的性能,就要在其他地方(比如,通用性、易用性、成本等方面)有所牺牲。

第二章:https://segmentfault.com/a/11...


JlDang
34 声望3 粉丝