要知道如何进行秒杀系统的优化,那我们需要先对请求的整个流程有个全局的认识。一般来说,秒杀活动请求以公网为划分点,可以分为:前端部分、后端部分。
前端优化
对于前端部分来说,常见的优化手段有:页面静态化 + CDN、请求频率限制(按钮置灰/loading)。
页面静态化 + CDN
因此,对于秒杀活动设计来说,我们可以将所有可以静态化的内容全部静态化,然后将其配置在 CDN 服务器上。这样既提高了用户打开页面的时间,又减少了后端服务器的压力。
请求频率限制
请求频率限制,指的是根据业务的特点,在前端做一些流量拦截,减少后端服务器的压力。常见的拦截方式有:
-
设定一个请求频率,例如 10 秒钟只能请求 1 次,随后按钮置灰。
后端优化
无论我们做多大的努力,始终还是会有不少流量会来到后端服务器这里。一般来说,后端的优化有如下几种方式:
-
增加缓存层 + 预热数据
-
MQ 异步处理
-
限流、熔断、兜底
-
业务端优化
增加缓存层 + 预热数据
如果我们所有数据都去读取数据库,数据库可能无法承受较大的流量,此时一个常见的优化就是增加缓存层。
当我们需要查询数据库之前,我们先去查询缓存,这样可以减少绝大部分的数据库请求,减轻数据库压力。如果在缓存中找不到数据,我们再去请求数据库,随后再将数据缓存到缓存中。
在引入缓存层的时候,我们需要考虑缓存击穿、缓存穿透的可能性,在写相关代码的时候就要做好这些优化。另外,我们在秒杀活动开始之前,可以手动将热点数据加载到缓存中,从而避免秒杀时去请求数据库。
MQ 异步处理
我们知道秒杀活动一般涉及抢购、下单、支付、发货等阶段,而抢购与后续的几个阶段是可以异步执行的。为了避免对下单、支付、发货等阶段产生影响,我们可以将抢购阶段与后续阶段用 MQ 进行解耦处理。当用户抢购成功后,往消息队列中丢入一台消息,随后再由订单系统消费进行下单处理。
通过各系统之间的解耦处理,我们可以将原本同步的处理方式变为异步处理,从而大大的减少了请求的处理时间,提高了系统的并发处理能力。其次,也能避免系统之间相互影响,提高了整体系统的稳定性。
限流、熔断、降级
虽然我们做了非常多的优化措施,但还是可能存在请求超量的可能性,那怎么办呢?
我们可以在每个业务系统做限流操作,从而避免因为请求太多,导致整个系统都无法工作。当并发请求在正常范围内时,我们正常处理请求。当超过设置的限流阈值时,我们则直接拒绝该请求,提示用户抢购失败。
如果没有限流操作,那么系统直接崩溃了,一个请求都处理不了。而通过限流这种方式,系统至少还可以保持正常工作,而不至于一个请求都处理不了。而超量的需求,本来就处理不了,因此提示失败也是情理之中。
除了限流之外,不同的系统还可以采用熔断、降级的服务治理措施。
熔断指的是请求的错误次数超过阈值时,不再到用后端服务,直接返回失败。同时每隔一定时间放几个请求去重试后端服务,看看是否正常。如果正常则关闭熔断状态,如果失败则继续快速失败。熔断的目的是避免因下游短暂的异常,导致上游不断重试,最终造成下游有太多请求,最终压垮下游系统。
降级指的是当服务失败或异常后,返回指定的默认信息。降级的目的是保证有基本的信息,当下游异常时,与其返回空信息,不如返回一个有业务含义的默认信息,可以提高用户体验。
业务侧优化
一般来说,经过上述的整体优化之后,系统已经能够比较稳当地应对秒杀活动了。如果此时还是流量比较大,那么或许应该从业务侧去进行优化了。
例如 12306 刚开始的时候,购买时间都在同一时刻,这导致同一时刻并发量太大,系统经常支撑不住。后来 12306 将购票周期放长,可以提前 20 天购买火车票。通过业务侧的优化,我们将本来在 1 个小时的抢购分摊到了 20 天,服务器压力一下子降低了 480 倍!
张晓龙也说过:如果公司最厉害的程序员来实现业务都觉得复杂,那很可能就是业务确实不合理,这时候应该从业务侧进行优化。
例如一个存储了 10 亿条记录的消息记录表,业务侧既想查询速度快,又想进行 1 年数据范围的数据查询,这无论如何都是无法实现的。这时候就需要从业务需求侧进行优化,否则是无法两全其美的。
对于这个场景,一个合理的实现方式是:要实现 1 年数据范围的查询,那么只能根据消息 ID 进行,因为这样可以使用上索引。而要根据时间范围进行查询,只能缩短查询时间到 3 天内,这样也可以满足业务需求。
因此从业务侧进行优化,是一个四两拨千斤的办法,可以极大地降低技术侧实现的难度。
总结
设计一个秒杀系统,整体而言可以从前端与后端进行优化。
对于前端优化而言,可以从「页面静态化 + CDN」、请求频率限制进行优化。
其中「页面静态化 + CDN」指的是将不变的静态数据固定下来,然后放入 CDN 服务器,从而提高用户请求的响应速度,降低服务器的并发压力。请求频率限制,则是通过抢购概率与抢购频率限制,降低后端服务器的服务压力。
对于后端优化而言,一般有「增加缓存层 + 预热数据」、「MQ 异步处理」、「限流、熔断、降级」、业务侧优化这 4 种优化方式。
其中「增加缓存层 + 预热数据」指的是将热点数据存入缓存,并在活动开始前提前加载到缓存中,降低数据库层的读取压力。「MQ 异步处理」指的是对于非必要的业务逻辑,通过 MQ 进行异步处理,降低请求处理延时,同时提高业务系统整体稳定性。
「限流、熔断、降级」是对于整体微服务的保护,其中限流指的是对请求进行限制,当超过限流阈值时,直接拒绝请求,保护系统本身;熔断指的是保护下游系统,当请求下游系统连续错误超过阈值时,自动不去请求下游系统,避免因重试流量过大击垮下游系统。
降级指的是当请求失败时,自动返回默认数据,提高用户体验。业务侧优化,则是指从业务层面去进行逻辑优化,从而降低技术复杂度,使得业务与技术复杂度达到一个平衡的状态,有利于更好地实现秒杀系统的高可用与高并发。
上面说到的 6 个优化思路,是设计秒杀系统常见的优化思路。但在实际业务场景中,除了要保障正常的功能设计之外,还还考虑防刷、安全、黑产等问题,此时可能需要多考虑一些其他优化,例如:黄牛利用抢 购工具抢购,导致正常用户无法抢到商品等。
这时候可能需要考虑增加验证码,用 App 设备指纹等风控措施。此外,对于秒杀系统而言,做好业务指标和系统指标的埋点监控也是非常重要的。