超大流量分布式系统架构解决方案

Scroll Down

需要总结下所有的内容。。。。

大规模服务化架构

全链路压测

当业务越发复杂、系统规模越来越大,以及外围资源依赖得越来越多时,系统中可能存在的各种不确定性因素也会随之被放大,甚至一个细微的错误都有可能导致交易系统出现雪崩。因此压测成为开发人员在大促前夕检测系统短板、瓶颈最有效的手段,为相应的风险点制定出有效的预案,才能避免大促时不被那些不确定性因素所带来的影响打个措手不及。

大促前夕最基本,同时也是最棘手的2项备战任务:

  • 评估机器扩容数量。
  • 验证系统整体容量是否能够有效地支撑所预估的流量峰值。

线上实施全链路压测的4个关键核心点:

  • 业务系统、中间件如何配合改造升级
  • 如何将压测数据引流到隔离环境中
  • 压测数据如何构造
  • 超大规模的压测流量如何发起

那么究竟什么才是全链路压测呢?在回答这个问题之前,大家首先需要明确一点:系统中任何一个接口都不会独立存在,假设A接口可以压测出1w/s的QPS,那么当A接口和B接口同时施压时,A接口的QPS势必会下降,原因其实很简单,因为受限于一些共享资源:简单来说,全链路压测其实指的是在特定的业务场景下,将相关的链路完整的串联起来同时施压,尽可能模拟出真实的用户行为,当系统整站流量被打上来的时候,必定会暴露出性能瓶颈,才能够探测出系统整体的真实容量水位,以及有指导地在大促前进行容量规划和性能优化,这便是线上实施全链路压测的真正目的。

业务系统如何区分压测流量

在为大家介绍业务系统如何区分压测流量之前,我们首先来谈论下研发同学比较关注的话题,业务系统是否需要配合进行相应的改造和升级,明确告诉大家,一定程度上会,因为对于线上所有的写接口来说,基本上是没有办法直接进行压测的,并且全链路压测任务并不会在业务初期就推动,一般都会选择在业务中后期才实施,尤其是当业务越来越复杂的时候,改造的难度和成本就会越大。

压测流量打标方案

线上业务系统如果想要准确区分出真实用户流量和压测流量,那么就必然需要对压测数据进行特殊的标记,并且这个压测标记还要能够顺利在一次请求涉及的所有后端服务调用的上下文中进行传递,当最终数据落盘或者调用第三方接口的时候,才能够做到不影响和污染线上数据。
test-note001.drawio

对压测数据进行打标的方式有许多种,这里列举了2种最常见的方式:

  • 在URL上进行打标
  • 在HTTP的header中进行打标

假设在URL上进行打标,如下所示:

# 正常URL
http://***/buyer/xx.json
# 打标URL
http://***/buyer/xx.json?st=true

当在URL上添加打标参数(st=true)并向后端业务系统成功发起请求后,如果业务系统检测到请求中已包含压测标记,那么就会把压测标记在一次请求的整个生命周期中一直流转下去。除可以选择在URL上进行流量打标外,在HTTP请求的header中打标似乎也是一个不错的选择。当然,具体选择哪一种流量的打标方式,还需要结合自身业务场景而定。

在链路上下文信息中传递压测标记

在上一小节中,介绍了如何对压测流量进行打标,以便有判断依据能够让业务系统区分出哪些是真实用户流量,哪些是我们的压测流量,当真正在线上压测时才不至于把压测流量误当作正常流量从而污染线上数据。对压测流量打标的方式非常简单,无论是在URL上进行打标,还是选择在header中进行打标都是可行的,判断一次请求是否是压测流量则需要在接入层就开始处理,如果检测为压测流量,当调用下游服务时,就需要能够顺利地把压测标记在一次请求的整个生命周期中一直流转下去。
在对业务系统发起一次HTTP对请求调用时,嵌套在分布式调用跟踪系统中负责流量区分的拦截器会优先对请求进行拦截,然后尝试从URL或者HTTP的header中获取压测标记,如果确认为压测流量,就将压测标记放进当前线程的ThreadLocal中,待调用下游服务时,再从中获取压测标记并放入Dubbo的RpcInvocation中,逐层向下传递即可。

外部第三方接口走Mock

诸如短信、物流,以及支付等一些外部第三方接口,实际上并不在压测范围之内,如果我们不对这些外部接口进行统一的梳理和屏蔽,那么在线上实际的压测过程中,将会产生一些不必要的影响。
当业务系统需要调用外部接口时,嵌套在分布式调用跟踪系统中的MockFilter会对其进行拦截,如果检测为压测流量,则匹配目标接口是否是外部接口,匹配规则可以直接在配置中心内添加黑名单设置,如果满足匹配,就直接调用Mock服务,Mock的具体结果同样也可以在配置中内设置,如果压测流量较大,运维仍然需要扩容较多的Mock服务来支撑压测请求。

压测数据的隔离方案

物理隔离和逻辑隔离2种方案。

为什么需要限流

类似双11这种场景下,总结了5种应对高并发、大流量的常规手段:

  • 扩容
  • 静态化
  • 限流
  • 缓存
  • 队列

由于单台服务器的处理能力极其有限,因此当一台服务器的处理能力接近或已经超出其容量上限时,采用集群技术对服务器进行扩容,可以很好地提升系统整体的并行处理能力,在集群环境中,节点的数量越多,系统的并行处理能力和容错性就越强。静态化其实是一个老生常谈的话题,简而言之,系统需要将动态数据和静态数据分而治之,用户对静态数据的访问,应该避免请求直接落到企业的数据中心,而应该在CDN中获取,以加速系统的响应速度。和现实生活中流量管制的场景类似,当网站举行大促活动时,那些单价比平时更给力,更吸引的热卖商品一定会吸引大量的用户前来购买,访问骤增的同时会带来读/写流量的骤增,因此需要采用合理且有效的限流手段对系统做好保护,毕竟不是任何场景都可以仅通过缓存和服务降级等技术手段就能够实现一本万利的。
大促场景下热点数据的读操作一直就是最核心的技术难题之一,通过缓存技术,系统在应对高并发、大流量时可谓如虎添翼,因为缓存的读/写效率要远胜于任何关系数据库,合理地使用缓存技术,系统的吞吐量将会得到质的提升,当触发流量高峰时,系统上下游对请求的处理表现必然不尽相同。当上下游系统处理能力存在差距,且对于那些不需要进行实时处理的请求来说,可以通过队列转储系统上下游的消息内容形成漏斗,待下游有足够的处理能力时再进行处理,以降低存储系统的负载压力,避免上下游逐层影响而产生雪崩效应。

大促抢购核心技术难题-读/写优化方案

热点数据的大并发读/写操作,可谓是秒杀、限时抢购等场景下最核心的2个技术难题。提升单机处理能力最有效的办法就是采用集群技术对服务器进行水平扩容,只要系统能够具备良好的伸缩性,那么从理论上来说,其容量便可无限延伸。在此需大家注意,大促场景下因热点数据导致的单点瓶颈已经不再是简单地通过水平扩容就能够解决的。针对热点数据的大并发读操作,尽管我们可以通过分布式缓存来提升系统的QPS,但是缓存系统的单点容量还是存在上限的,一旦超过临界水位,分布式缓存容易被瞬间击穿。而热点数据的大并发写操作,势必会下潜至数据库,那么这就会引起大量的线程相互竞争InnoDB的行锁,并发越大时,等待的线程就越多,这会严重影响数据库的TPS,导致RT线性上升,最终导致系统发生雪崩。
我们在实际开发过程中缓存产品无非也就是本地缓存和分布式缓存两大类,当然无论是使用本地缓存还是分布式缓存,其目的都是解决如下两个问题:

  • 降低下游存储系统的负载压力。
  • 提升系统的响应速度。

本地缓存的痛点

本地缓存的优点非常明显,那就是读/写性能非常好,但它同时也存在如下两个痛点:

  • 占用应用系统的内存资源
  • 数据一致性问题