This commit is contained in:
louzefeng
2024-07-11 05:50:32 +00:00
parent bf99793fd0
commit d3828a7aee
6071 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
<audio id="audio" title="01 | 容量保障的目标:容量保障的目标是什么?该如何度量?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/9c/f8/9c4a2bfc1879fa8590abef282087b5f8.mp3"></audio>
你好,我是吴骏龙,欢迎和我一起学习容量保障。
俗话说万事开头难,在没有弄清楚目标和需求之前,很难进行容量保障,这就好比建筑图纸没有设计出来之前,你肯定不会开始砌墙。此外,不同角色看待容量的视角也是不一样的,对用户来说可能是想用的功能正常,访问速度快;而对技术人员来说,则是某个性能指标或可用性指标达到可靠的范围。
<img src="https://static001.geekbang.org/resource/image/e9/e8/e9363d72203ac5159d5c011f6abeb2e8.png" alt="">
在今天这一讲中,我会着重和你讨论技术视角的目标,但同时也要明确,任何技术目标最终都是要体现到业务,也就是终端用户上的,**脱离业务场景制定容量保障的目标,几乎肯定会跑偏**。因为不同业务场景对于容量保障的要求是不一样的。
举一个极端的例子,如果我们面对的是企事业单位的某个内部系统,有着非常稳定的用户规模和几乎不变的产品功能,那么容量保障就是基于固定用户量的一次性保障工作。相反,如果是大型电商系统,业务场景有明显的流量峰值,且经常举办大促活动,容量保障就是一部“跌宕起伏的连续剧”。
## 容量保障的目标是什么?
那么,容量保障的目标究竟是什么呢?我们先来回答这个问题吧。
总结一下其实就两句话:
- **第一,以尽可能小的成本确保系统当前和未来的容量充足,即容量规划;**
- **第二,解决已知的容量问题,预防未知的容量问题,即容量治理。**
我们的这门课,就是围绕这两方面层层展开的。
你可以按这样的思路去理解容量保障的目标。首先成本是容量保障的一个制约条件容量保障不是无限保障公司对服务器等IT资源的投入对容量保障人力资源的投入等等可能都会设置上限这些都是成本上的约束。
在控制成本的基础上,我们要保障服务容量充足,即服务的各项资源消耗和业务指标保持在一个相对安全的范围内,这个范围可以是推算出来的,也可以是通过容量测试验证出来的,亦可以是真实流量体现出来的,我们将其称之为“安全水位”。
最后,分布式系统中充满了不确定性,网络可能抖三抖,硬盘可能崩一崩,我们一方面要尽可能在这种不可靠的环境下预防容量问题的发生,又要在出现容量问题时,有能力在短时间内消除影响,甚至是全自动的进行止损,这一点直接影响着服务可用性和用户体验。
做到了这些,容量保障的目标自然就达成了。
## 容量保障目标的量化
在明确了目标之后,我们需要拆解出一些具体的量化指标,以确保目标的有效达成。换言之,如果公司将容量保障的任务交给你来完成,你怎么证明自己的工作完成得好不好呢?
这时候,你就需要去量化目标,用数据说话。一个不能量化的目标,本身就是难以实施的目标,这也是为何我们在制定各种目标时都建议输出度量指标的原因,关键结果是由量化指标的形式呈现的。
那么,容量保障工作中有哪些关键的量化指标呢?
### 1. 服务等级协议SLA
通俗地说SLA就是对服务可用性的一个保证它可以细分为SLI和SLO。其中SLI定义测量的具体指标如QPS、带宽等SLO定义服务提供功能的期望状态如QPS 99线≤100ms。
**SLA用一个简单的公式来描述就是SLA = SLO + 后果。** 这里的后果指的是不满足SLO情况下的补偿协议比如赔款、延长使用期等等。
可用性是互联网系统提供服务的根本因此用SLA作为容量保障目标的量化指标也是非常常见的。当然不止是容量问题有很多因素都有可能影响SLA比如线上漏测的Bug、网络抖动、服务器断电等等因此需要识别出影响SLA的容量问题再判断是否满足目标。
举个具体的例子我们要求系统整体可用性SLA为4个999.99%即每年不可用时长≤52.56分钟1年8760小时 × 0.0001 = 52.56分钟)。
基于这个整体SLA要求并综合考虑历年容量问题对服务可用性的影响比例比如占比为1/5最终设定容量问题造成的可用性损失不高于10分钟52.26 / 5≈10分钟这就是一个明确的目标基于这个目标拆解策略是可衡量的。
不过,虽然**SLA是一个很好的指标但也是众所周知的易量化、难测量**。
举个例子有一项SLA承诺了团队将在24小时内解决用户上报的问题但它却没有讲清楚如果客户没有提供足够的信息反复沟通的时间如何计算24小时是否包含这些时间这些信息是必须要落实的但其实很少有团队能将SLA描述细化到这个程度。因此很多SLA的制定其实是不太切合实际的我们应该用尽可能浅显易懂的语言围绕业务或用户的实际需求制定能测量、能理解、有效的SLA。
上面说了一个反面教材,我针对容量保障工作再给你一个优秀的案例吧。
如下图所示我们将交易链路下单接口的成功率≥95%作为SLA的一部分并且承诺低于该成功率的时长不超过1分钟这就是一个容易理解且可测量的SLA通过对下单接口的监控就可以观测。交易链路的容量问题有导致下单成功率下跌的可能性因此作为容量保障的目标也是合理的。
<img src="https://static001.geekbang.org/resource/image/c0/f4/c0e6e5c70914f8babdb9038713d97df4.png" alt="">
### 2. QPS/TPS
第二个关键的量化指标QPS/TPS我们先来复习一下它们的含义
- QPSQueries per Second指的是每秒查询率是一台服务器每秒能够响应的查询次数即1秒内完成的请求数量一般针对读请求居多。
- TPSTransactions per Second指的是每秒处理的事务数一般针对写请求居多。
如果你觉得不够形象可以想象一下百度的搜索页面假设我们将这个页面的展示过程视为是一个事务每秒对这个页面的请求就形成了TPS其中可能包含对若干页面内请求的QPS即1TPS多QPS。如果我们只是请求一个静态页面页面加载不包含其他查询请求那么这里TPS和QPS就是对等的即1TPS1QPS。
QPS/TPS是容量保障目标中最常见的指标**我们通常说“系统容量是否足够”一般就是指系统或服务能否在可接受的响应时间和成功率下支撑目标QPS/TPS**。
不过在实际工作中我们有时可能无法直接给出QPS/TPS的目标值比如说针对某个将要上线的大促活动业务方预估的活动热度往往是以业务指标的形式呈现的如PVPage View、UVUnique View、DAUDaily Active User我们需要将其转换为QPS/TPS才能作为容量保障可实施的技术目标。
为了加深理解,我来出一道应用题。
这里有一个活动页面页面上分为A、B和C三个区域进入页面分别调用getAct()、getAct2()和getAct3()接口各一次这些接口的调用链路又会涉及a()、b()、c()三个接口调用关系如图所示。这时如果业务运营方给到这个页面在活动期间1天的总PV预估是1000万求a()接口的预估QPS是多少
<img src="https://static001.geekbang.org/resource/image/a5/fc/a5cb552fbecf7fe980276ebb29aba1fc.png" alt="">
首先1000万PV是分布在整个活动期间的但不一定是均匀分布的。假设我们根据二八原则也就是80%的PV分布在20%的时间内4.8小时中将有800万PV平均每秒463PV。
由于进入该页面1次PV对应getAct()和getAct2()接口各调用一次那么对a()接口的调用总共就是2次我们可以得出a()接口的预估QPS为926这就是该接口在活动期间的容量保障目标。
总结一下不论是计算QPS还是TPS首先需要对服务调用链路非常熟悉梳理出调用关系最好能够形成类似上面例子中的调用关系图这样会更清晰易读其次虽然针对页面入口的流量是等比例调用的但根据上述例子我们也看到了1次PV转换到a()接口变成了2次调用这意味着对下游服务的调用量很有可能会被放大这些扩散比是需要重点计算的最后如果是针对局部活动的流量预估还需要考虑到接口在其他链路上的背景流量也需要一并计算在内例子中的c()接口就存在这样的背景流量。
如果你感兴趣的话可以计算一下对于c()接口的预估QPS应该是多少呢
再多说一句传统的互联网服务大多是计算密集型的即并发量较大的类型QPS/TPS和响应时间比较适合作为容量目标。而对于数据存储型的服务比如某些大数据服务吞吐量和磁盘IO是比较合适的目标因为这种类型的服务对计算量的要求不大主要瓶颈在数据传输的速度上具体你可以看[这篇文章](https://www.cnblogs.com/sddai/p/8647795.html),解释比较全面了。可见,制定目标是要因地制宜的。
### 3. 用户体验
第三个关键指标是用户体验。有些容量问题尽管没有影响可用性但会导致用户操作时响应延迟页面打开缓慢等体验问题。想象一下你工作了一天下班回到家躺在床上打开某个电商App准备看一下有什么新品上市结果每浏览一个商品详情页都会卡上好几秒你会是啥心情呢
其实,我们都希望系统始终能够为用户提供平稳、快速的用户体验,不仅要“可用”,还要“用得爽”。因此,**用户体验完全可以作为容量保障更高级的目标**。将用户体验做到极致,是咱们每个互联网技术人员都应该铭记的初心。
不过用户体验问题的定性是相对困难的一种手段是将客户投诉或内测版本反馈作为一个维度去跟踪。另外绝大多数用户体验是可以与系统指标或业务指标挂钩的这些指标就可以作为目标的一部分。比如有用户反馈某个操作等待时间特别长其涉及的接口背后的服务器CPU利用率、内存利用率、响应时间、调用的消息队列延迟等信息就都可以作为参考维度。
## 总结
今天这一节课,我首先介绍了不同人群看待互联网服务容量的视角区别,并明确了从技术视角出发,结合业务场景的思路。
接下来,我重点解释了容量保障的目标,你可以将其拆解为容量规划和容量治理两部分。前者考虑在成本的约束下,将系统资源规划到最优水位;后者则主要致力于容量问题的事前防治和事后止损。
最后我详细展开了容量保障目标的量化方式和指标选取分别就SLA、QPS/TPS和用户体验三方面进行了阐述。SLA是基于服务可用性的视角来量化容量保障目标的QPS/TPS则是以服务处理能力作为容量保障的度量维度用户体验是最高级的度量指标直接以用户的感受作为容量目标。
**技术指标联系业务场景,量化目标结合用户体验,是我想传达的核心思想。** 产品是做出来给人用的,容量保障的终极目的,也是竭尽所能给用户提供流畅的产品体验。互联网业务的快速发展对容量保障提出了越来越高的要求,今天制定的目标也许很快就会跟不上明天的发展方向,用户体验就是一个典型例子,直到今天都很少有人将其作为容量保障的目标,但它恰恰是一个产品的核心竞争力。我们应该以动态的眼光看待容量目标,不断精益求精,更好地服务用户。<br>
<img src="https://static001.geekbang.org/resource/image/ab/7e/ab7fc7d46c4d2c8bf8b4d6cca75dbe7e.png" alt="">
## 课后讨论
在“QPS/TPS”小节中我留了一个小问题你可以计算一下c()接口的预估QPS是多少注意考虑清楚所有的请求来源。欢迎你给我留言也欢迎分享给更多的朋友一起阅读。

View File

@@ -0,0 +1,153 @@
<audio id="audio" title="02 | 容量测试与验证:怎样科学实施容量测试?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/90/ed/90b5208a5c87ff2df5a517aeb8fdc0ed.mp3"></audio>
你好,我是吴骏龙。今天我会和你分享容量测试与验证的话题。
相对于性能测试和压力测试这些耳熟能详的名词“容量测试”这个词也许你是第一次听到。在百度、Google上一搜结果倒是不少但很多解释过于陈旧并没有跟上互联网的发展速度。比如
>
容量测试就是以压力测试的方式对服务施压,在相关容量指标达到瓶颈时停止,这时探测到的系统水位就是最大容量。
这个解释本身没什么毛病,我们很多时候也会把容量测试直接叫做压力测试,但有几家公司在执行容量测试时会真的压到瓶颈呢?如果你以这样的定义践行容量测试,在微服务体系下几乎是落不了地的。因为很多时候,我们并不需要去探测服务的容量极限。
其实,问题的本质在于,传统对容量测试的认知都希望能够获得一个瓶颈点,这是以压测的视角来看待它的。但绝大多数时候,我们都是根据预先制定的容量目标,通过对服务施压来观察和验证服务能否承载这一目标,并不是非要压出极限值。
我个人非常喜欢阿里前任CTO行癫在2018年双11启动会上说的一句话**“容量测试是验证手段,不是测试手段”。** 换句话说,我们应该先努力设计和建造出满足容量要求的服务,再通过容量测试去验证它,而不是靠容量测试去反复探测服务容量瓶颈,再去不停地优化服务或扩容。我认为这才是对容量测试的现代化理解。
说得更接地气些,**容量测试不是极限保障。** 你也可以形象的理解为,**压力测试是先斩后奏,而容量测试则是有备而来。**
下面我们就来具体展开,看一下容量测试该怎么做。
## 确定容量测试的范围
在进行容量测试前,我们先要弄清测试的范围。
容量测试的对象是服务,对于专项场景,比如大促活动场景,梳理出活动所涉及的服务和依赖服务,将其纳入到容量保障范围内就可以了。而对于日常场景,除非服务规模很小,否则不大可能将所有服务都全盘覆盖,这时就应有所取舍。
一种比较经济的方式是风险驱动,即**针对容易产生容量风险的服务重点考虑进行容量测试**。那么,问题来了,哪些服务最容易出现容量风险呢?下图为你做了一定的概括,我来展开讲解。
<img src="https://static001.geekbang.org/resource/image/a7/00/a710f80cf35232e72d34856e4f433d00.png" alt="">
**第一,关键路径上的核心服务**肯定是重点保障对象。倒不是说这些服务就一定会有容量风险,而是一旦出现风险,影响会比较大。此外,被关键路径上的服务依赖且无法降级的服务,也应该看做是关键服务,它们是一条绳上的蚂蚱。
**第二,有明显流量峰值特征的服务**,比如高峰期和低峰期的流量差异非常大的服务,或者是经常举办活动会造成流量突增的服务。这种巨大的流量差异容易引发服务容量风险。
**第三,对响应时间敏感的服务**,有些底层服务经常被上游服务在同一次请求中调用好几次,一旦响应时间上升,汇聚到上游服务的总响应时间会被放大好几倍,这种服务的容量就要特别小心。当然,在链路调用中也要尽量避免这种多次调用的情况,尽量批处理。
**第四,占用资源大的服务**,比如占用大量带宽、占用大量内存等,容易造成资源耗尽的服务,就容易引发容量问题。
另外,除了关注容易产生容量风险的服务,对于**历史上曾经发生过容量事故的服务、目前高峰期已经存在容量隐患的服务、新上线对容量情况未知的服务**,也都要重点进行容量测试。
## 科学实施容量测试
确定了容量测试的范围,我们具体看一下如何实施容量测试。
容量测试工作一般可以由负责性能测试的技术人员或运维人员主导,拉通各个团队的协作,定义清楚流程规范,由业务团队配合做好**事前方案、事中盯盘和事后分析**。
当然,无论你是什么角色,都需要以全局视角看待容量测试工作,了解每个环节要做哪些事情,这样才能更好地相互协作。下图就是实施容量测试的全局流程图,基于这张图,我来具体展开每一个重点步骤。
<img src="https://static001.geekbang.org/resource/image/57/62/5797d0fc5e0a6ee3d2308934d3893e62.png" alt="">
### 1. 测试方案设计
也许你不太喜欢写测试方案,我猜一部分原因是程序员都更愿意写代码,而不是码字,我写这个专栏是个例外;另一部分原因大概是你很自信,认为即便不写测试方案也能完成测试工作。
但我想说的是,**测试方案是写给自己,更是写给团队看的**,这是你将信息通过一种形式传达给外部的过程,缺少这一过程,随之而来的就是潜在的误解和信息不对称,是有非常大的隐患的。
此外,**测试方案是可以模式化的**,其本质是经验的一种抽象和固化。比如说设计模式,现在你可以通过阅读各种资料去学习已经归纳好的设计模式,但这些设计模式可不是一开始就有的,我们的前辈在工作中不自觉地践行了一些好的做法,并将这些做法抽象提炼出来,才形成了现在看到的各种设计模式。
所以,对测试方案的实践,我建议也遵循同样的原理,先集众人所长,抽象总结出一份适合你团队和业务特征的模板,在测试方案设计时,照着这个模板填空就行了。
这样做的好处有很多。
首先,这份模板已经为你准备好了纲要,是带有备忘性质的,在大方向上你不会再遗漏一些重要的工作;其次,模板是标准化的,是一种潜在的“契约”,这能够降低团队的理解成本,在评审时特别有用;最后,这种形式也方便日后追溯和反查,相当于建立了一份档案。
我这里给出一个较为通用的容量测试方案设计模板,你可以基于它,结合实际情况进行再加工。需要注意的是,涉及到的降级方案和补偿方案等止损策略,一定要在线上提前演练过,否则真将业务压出问题来了,操作降级时却又发现无法降级,那麻烦就大了。
<img src="https://static001.geekbang.org/resource/image/76/97/767b9e03ccc18e0f8886f33b29612997.png" alt="">
### 2. 测试方案评审
一个好汉三个帮,也许你非常善于容量测试,也精通业务场景,但人的疏忽是客观存在的,只是概率问题而已。评审工作的目的就是通过交叉审查的方式,尽可能避免个体的疏忽,降低这个概率。
在测试方案评审中,相关研发人员和测试人员都要参与评审,确保测试模型和数据合理,没有遗漏关键信息。对于关键服务、重大活动或复杂场景,建议有架构师进行二次复核。
为了避免评审过程枯燥乏味,我们提倡**内容正式、形式轻松、集中精力、高效评审**。当时在我的办公楼层,有一台可移动的电视机,我们把这台电视机推到茶水间门口的沙发边上,每人拿上一瓶饮料就开始评审了,除了主讲人以外其他人不允许带电脑,评审在一小时内完成,偶尔有超时的,另行预约时间。
你可以学习一下这种正式又轻松的评审方式,并不需要每次都把所有人拉到会议室,大家正襟危坐的轮流发言,这样反而很限制思维的迸发。
### 3. 测试准备
测试方案确认无误后,容量测试人员就可以开始着手进行准备工作了:根据评审过的场景撰写测试脚本,准备测试数据。准备完毕后,调试脚本和数据,确保能够正常执行,服务无异常。
关于测试脚本的编写我在这里不做展开不同的工具有不同的用法而且常见的开源性能测试工具JMeter、Gatling、nGrinder等的学习曲线都不是很陡峭你可以直接去这些工具的官网查阅文档 ,都有完善的用户手册和使用案例。
关于测试数据的准备,你可能要问这样的问题,比如:准备多少测试用户?这些用户中有多少比例需要设置成会员?等等。诸如此类的问题,其核心其实就是一句话:**“尽可能贴近真实的业务场景”**。
上面提到的“准备多少测试用户”的问题展开来说由于真实生产环境中用户数据量较大大多数情况下在数据库层面都会采取分库分表的做法将用户ID散列后路由至多个分片表存储。
如果我们准备的压测用户数量过少,那么这些用户很容易就会集中到某几个分片表上,在压测时导致单片过热(某几个分片表的负载特别高),这就与真实场景相违背了,压测结论自然也就没有意义。因此,我们在准备压测用户时,需要达到一定的数量规模,至少要保证这些压测用户能够均匀分布到每个分片表中。
上面还提到这些用户中有多少比例需要设置成会员呢思路也是一样的以真实业务场景为准。假设在实际业务中会员与非会员的数量占比为15那么我们在设置压测用户的会员比例时也可以遵循相同的比例关系。
### 4. 测试执行
准备工作一切就绪后,下一步就是执行容量测试。容量测试一般在线上执行居多,除非在线下能构建出完全对等的环境,否则即便将服务规模和硬件资源等比例缩放,容量的表现情况也不一定是线性的。
当然,线上测试的风险较大,我个人工作中也遇到过因测试数据不严谨(夹杂了真实数据)导致事故的情况,因此需要有严格的操作规范和止损预案。此外,线上测试如果涉及写流量(会写入数据的流量),还需要进行数据隔离、业务逻辑过滤等一系列工作,在进阶篇的全链路压测一讲中,我会再与你详细展开介绍。
无论使用何种测试工具,测试执行的流程和规范都是类似的,下面给出一个较为通用,且比较安全的推荐流程。
<img src="https://static001.geekbang.org/resource/image/a8/4d/a8df1abb3ce0b4111a175b4102bd894d.png" alt=""><br>
在这个流程中,容量测试是循序渐进的过程,逐步对目标服务施加压力,期间需要严密监控各项指标,一旦出现异常,应确保无风险的情况下才能继续施压。在达到容量目标值后,可以同时进行适当的摸高(在更高压力下维持一段时间)和脉冲(模拟瞬时的高并发场景),或对限流进行验证等工作。
**由于我们事前并不知道系统实际是否能够承载预估的容量,所以容量测试是一种较为高危的验证过程**。我再列举一些常见的容易导致测试过程影响线上业务的情况,你一定要多加注意:
- 直接压到容量预估峰值,风险极大;
- 只进行测试,不观察监控,出了问题也不知道;
- 单次测试时间过长,不符合实际情况;
- 没有止损预案,出了问题手忙脚乱;
- 对目标业务不熟悉,尤其是上下游链路,把生产环境作为试验场。
### 5. 测试反馈
容量测试结束后,要有明确结论,总结测试过程中的各项指标和数据,与各方确认数据结论是否正常以及是否达到预期,编写测试报告,输出结论。
这里有一些注意点:首先,测试数据要保证真实有效,有时候在测试中可能由于各种原因导致当轮测试没有跑完,数据不完整,那么就应该抛弃该数据。其次,测试结论要简明扼要,对于无法确诊的信息也要清晰描述,暴露风险。最后,如果因为一些可测性的原因,导致测试结果有一定的局限性,也应该在报告中明确告知。
总之,测试报告要力求在最小的篇幅内,给出人人都能看懂的结论。
### 6. 持续跟进
容量测试不是单纯的测完就好,暴露的问题需要有效跟进,并在一定时间内跟踪解决,改进后确定时间再次进行验收,确保改进措施有效。
好了,到这里为止,我已经讲解了容量测试工作的整个实施过程,其中涉及的点还是比较多的,你可以按照公司的实际情况和人员投入,对具体内容进行加工。
此外,这套流程在团队内要有效地运作起来,是需要有运营动作和配置制度的,**在我的团队中,我会要求在项目技术方案评审阶段,甚至是需求阶段,容量测试人员就应介入熟悉业务场景**这样在评估目标后就能非常快速地设计出测试方案尽早进入评审流程。容量测试结束后针对发现的问题相应的研发负责人必须在3个工作日内给出解决措施并约定再次验证的时间。这些制度都是确保流程能够落实的必要手段。
## 另一种容量测试:基线容量测试
说完了传统的容量测试,我们来换换口味。
前面我提到了,容量测试最好是在线上环境实施,因为在线下很难构建对等的环境。不过,有一种方式可以让我们在测试环境以较低的成本先“定性”的识别出容量差异,以便提前发现可能存在的容量隐患,这种方式称之为基线容量测试。
基线容量测试在线下测试环境就能完成,具体的做法是,我们需要按照与线上相同的部署方式搭建这套测试环境(下称“基线环境”),包括所有的中间件和网络设施,不过**资源规模可以等比例减少**。之后,将当前各服务的主干版本部署在基线环境上,并通过容量测试的方式获取容量指标记录备案,这些指标就称之为“基线指标”。
我们假定基线指标是符合容量要求的接下来当有服务准备发布新版本时就可以在基线环境上部署这个新版本再执行同样的容量测试将所获得的指标与基线指标进行对比如果出现关键指标的大幅异动如响应时间暴增、CPU利用率暴增等情况就需要介入排查风险。
基线容量测试虽然没有办法对服务的容量进行定量分析因为基线环境与生产环境不对等但是可以一定程度上提前发现潜在的容量隐患而问题早发现的修复和优化成本是最低的。基线容量测试的另一个好处是很容易自动化也能够很轻易地与CI/CD流程打通这又能进一步降低成本。
## 总结
这一讲我重点与你讨论了容量测试的定义、范围和实施过程,也就一些争议概念给出了我的观点。现代化的容量测试,提倡目标先行,将容量测试定位为验收手段,规避容量不足等潜在风险。
容量测试作为一项需要科学实施的工作,涉及多个环节,包括:测试方案设计、测试方案评审、测试准备、测试执行、测试反馈和持续跟进这六大工作内容。你可以按照实际情况,对我给出的方案进行加工。
另外,线上实施容量测试还是有一定成本的,为此我提供了另一种思路,通过在线下环境进行容量指标基线对比,能够在一定程度上提前发现明显的容量隐患。
希望今天的讲解能够帮助你在团队内建立一套科学高效的容量测试流程。<br>
<img src="https://static001.geekbang.org/resource/image/07/90/07791721a1b16c472543110a6dae4990.png" alt="">
## 课后讨论
想一想在你的团队中如何实施基线容量测试的自动化并将其集成至CI/CD流程中欢迎你给我留言也欢迎分享给更多的朋友一起阅读。

View File

@@ -0,0 +1,112 @@
<audio id="audio" title="03 | 容量指标分析经典5问响应时间真的是越短越好吗" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/88/f3/8886184c352b22a3561dc6938f8b5bf3.mp3"></audio>
你好,我是吴骏龙。今天咱们多聊聊干货,我会与你分享和解答容量指标分析的几个经典问题。
有名言道“数据是钢,分析是铸造”,容量指标只是摆在桌面上的数据而已,要让这些数据产生价值,需要通过分析挖掘出背后深藏的容量隐患。如果能练就一双火眼金睛,从这些纷繁复杂的指标中快速识别出潜在的容量隐患,就能最大程度上规避可能发生的容量事故。你不仅将成为一名高手,还能为公司创造巨大的价值。
不过,在实践中我发现分析容量指标还真是一项极具挑战的任务,其中很大一部分原因在于,系统容量受制于多种因素,牵涉到多个指标,复杂程度远远超过想象。下图是我分类整理过的指标集合,你可以看到,分析容量指标需要对服务架构、中间件、服务链路等环节都有深入理解,这就导致很多人一上来就撞了南墙,颇有“从入门到放弃”的感觉,坚持下来的人也往往会遇到各种误区,艰难前行。
<img src="https://static001.geekbang.org/resource/image/de/2c/deaa7dc19537f081ea8f4e592bfef02c.png" alt="">
容量指标分析作为一项实践性很强的工作,是很难通过理论学习全面掌握的。因此在这一讲中,我会直接通过“问题驱动+案例分析”的方式进行讲解。这些问题都是我在实践中遇到的经典问题,也是很多初学者的高频困惑点,你可以结合这些思路,在实践中多去尝试,相信很快你就能成为容量分析的大牛。
闲言少叙,我们直接进入正题。
## 问题一:响应时间到底是关注平均值,还是分位线?
响应时间是指从发出请求开始到最后收到响应所需要的时间,作为服务容量最显著的反馈指标,响应时间是最需要引起我们重视和全面了解的。针对这个问题我先说结论,对于互联网服务,**响应时间应更关注分位线**我们常说的TP95、TP99或95线、99线这类称呼就是指分位线。分位线的概念不难理解将所有请求的响应时间排序取前95%中最后一个请求的响应时间即为95线它表示至少有95%的请求响应时间小于等于这个值。
关注分位线甚于平均值的主要原因在于,平均值很容易“冲淡”一些耗时较长的请求,导致容量问题被掩盖。
考虑一个场景某服务的常态响应时间为100ms可接受的最大响应时间为150ms当服务负载升高至接近瓶颈时有约20%的请求响应时间增加了一倍达到200ms也就是说大约有20%的用户有可能已经受到影响。我们简化一下问题假设考虑100个请求这时平均响应时间是120ms[(80×100ms + 20×200ms) / 100=120ms]看似还好而95线已经达到了200ms排序后第95个请求响应时间为200ms显然95线更容易发现容量隐患。
以分位线作为响应时间关注点的本质在于,尽管只是小部分请求的响应时间增长,但服务容量已经处于不充足的萌芽状态了,这时候如果不加干预,很有可能服务容量会迅速恶化。因此,虽然这个问题是针对响应时间的,但其实可以推广到很多地方,比如数据库的读写耗时、缓存的读取耗时等等,都应当关注分位线。
## 问题二:响应时间一定越短越好吗?
这又是一个关于响应时间的问题,针对这个问题,你可能会说,响应时间作为一个直接能被用户感受到的外部指标,肯定是越短越好啊,真的是这样吗?我们来看一个案例。
下图展示了某服务在进行容量测试时的现场监控情况可以看到服务的响应时间95线始终保持在35ms以下对于这个服务而言是非常理想的响应时间但这时负责盯盘的运维人员却告诉我们目标服务抛出了大量的异常这是为什么呢<br>
<img src="https://static001.geekbang.org/resource/image/5a/f9/5a7299f77c64e6199124f1cb477519f9.jpeg" alt=""><br>
当时负责测试的同学是一位新手查看了压测日志才恍然大悟原来几乎所有的请求都返回了错误的响应体当然服务本身的状态码设置也有问题无论请求正常还是异常一律都返回了200。进一步排查发现测试数据存在问题导致对该被测服务的测试请求始终会走入异常分支主体的业务逻辑都没有经过响应时间当然就短了。而这位测试同学也没有对响应体设置断言未能在第一时间发现这个问题。
**响应时间越短越好,是建立在场景正确,服务无异常的基础上的。** 上述这个问题虽然不属于服务的容量问题,但是在容量测试过程中时常会出现,如果仅以响应时间为观察目标,就会得到错误的容量判断,最终无法达到容量保障的效果,这是初学者很容易犯的失误。
解决这个问题的思路也很简单,就是**加强全方位的指标监控**关注响应时间的同时还要关注错误率、TPS、请求成功率和异常率等指标。我的团队在每次进行容量测试前就会与研发一起先将这些需要观察的指标配置成一个简单的监控面板在执行测试时可以方便观察这样就能最大化地预防这个问题的发生你不妨可以参考学习。
## 问题三CPU利用率一定越低越好吗
响应时间不是越低越好那么CPU利用率是不是越低越好呢
我们知道CPU是一个计算机的核心计算组件CPU利用率代表了CPU工作的饱和程度指CPU工作时间占总时间的百分比。
那如果CPU利用率低是不是服务就一定没有容量问题呢答案是否定的我们来看一个例子。
下面有两张监控指标图展示了某服务在相同时间段的响应时间和CPU利用率情况。可以看到在0900 - 0935这个时间段服务的响应时间暴增已经严重影响了线上功能但CPU利用率始终维持在一个较低的水位图中纵轴为所有CPU核心的总利用率该服务CPU共有8核总计上限为800光看CPU利用率似乎没有观察到任何问题。
<img src="https://static001.geekbang.org/resource/image/47/19/47b8212685db19e58b4d7339bafcbe19.jpeg" alt="">
<img src="https://static001.geekbang.org/resource/image/e7/51/e7aff949dbcf1484267dbf28ae9fab51.jpeg" alt=""><br>
我们顺着服务链路继续排查,发现该服务有大量调用数据库的操作,而在发生问题的时候,数据库的查询耗时大幅增加,似乎问题已经有了眉目。
再往下深挖我们发现该服务使用了线程池去处理业务线程池使用了ForkJoinPool默认大小为CPU核数8核
```
CompletableFuture&lt;Map&lt;String, XXDTO&gt;&gt; future =
CompletableFuture.supplyAsync(
() -&gt; xxService.getXX(id)); //未自定义线程池默认使用ForkJoinPool
```
但处理的任务却伴随着大量数据库查询等IO操作。这时一旦数据库负载增加耗时变长后线程就会被长时间阻塞由于线程池过小导致后续任务只能排队。遗憾的是排队的队列又是一个无界队列从而形成了恶性循环响应时间暴增。
查到了根因,解决方法也就很简单了,将线程池的大小重新调整,并优化排队策略,就可以避免这一问题。
**因此CPU利用率低只能说明CPU不忙并不能说明在其他地方没有容量瓶颈。** 在上面这个例子中,容量瓶颈发生在了数据库上,也许在其他场景中,瓶颈还会发生在缓存,或是对其他服务的同步调用上。因此看待这个问题的视角与“问题二”是类似的,需要联动多个指标一起去分析和排查,不要只关注单一指标。
## 问题四:压不上去了,就是服务容量达到瓶颈了吗?
在容量测试时我们也会遇到一些指标判断的误区比如在提升了施压端的输出压力后服务的TPS并没有明显提升那是不是就可以说服务容量达到了瓶颈呢
首先,我要明确的是,服务容量是否达到瓶颈,并不是靠施压端是否能“压上去”来判断的,而是**依靠服务端的容量指标去判断的**。怎么判断呢?很多资料会告诉你找拐点,但很遗憾,现实中这样的拐点不太会出现,除非你真的不惜代价地增加压力。
一般来说如果服务一切正常当增加压力时TPS是会呈比例上升的同时响应时间比较稳定。如果TPS上升的速率开始变缓这时候其实容量可能已经出现瓶颈了你可以再结合响应时间和服务资源指标确诊。
那么,为什么不能靠施压端的现象去判断呢?道理也很简单,**因为压不上去,不一定就是服务不行,有可能是施压端自身出现了瓶颈**。
在容量测试过程中如果你发现增加压力后服务的TPS没有提升但响应时间也没有明显的增加可能还会有一些抖动这时你一定要检查一下压测端的资源消耗情况。
类似JMeter这样的压测工具是基于传统的BIO阻塞式IO线程模型的一个线程同时只能处理一个连接而单机能够支撑的线程数总是有极限的达到这个极限后单纯调高施压端的线程数参数实际并不会带来更高的真实线程数也不会增加对服务端的压力。你可以检查压测端的CPU利用率来判断如果CPU利用率已经打满就需要增加新的压测节点了。
此外,带宽也是一个常见的制约压测端能力的指标,尤其是当响应的返回体很大的时候,就比较容易打满带宽,这种情况甚至会影响到正常服务的访问,一定要小心。涉及多数据中心的服务可能还会遇到跨地区专线带宽打满的问题,也都是需要关注的。
总结一下在容量测试过程中如果遇到压不上去的情况对施压端的资源消耗要留个心眼不要轻易认为就是服务容量不足了。此外在实践中施压端瓶颈几乎都发生在压力机的CPU和带宽消耗上。因此我在推动压测自动化实施过程中将施压端的监控也纳入到了自动化体系里面一旦施压端出现资源瓶颈就会自动告警提示测试人员。如果你觉得这招不错可以在你的实践中尝试一下。
## 问题五:指标只是偶尔“抖动”一下,要不要关注?
上面聊到的问题中很多指标都是可以定量判断容量风险的比如响应时间99线超过某阈值、CPU利用率超过某水位等等。但是如果这些指标只是偶尔抖动一下我们要不要关注呢
当然要关注,抖动是一类很容易被忽视的场景,我曾经看到一个服务每隔一段时间,响应时间会突然飙升一个尖刺,询问了服务负责人,对方很不以为然,表示这种情况一直存在,从来没有造成过什么影响,觉得我有点小题大做,结果在高峰期这个服务还真出事了。
**没有找到根因的抖动是很危险的**,因为你根本不知道它未来会不会导致大事故的发生。我们再来看一个例子,如下图所示,同样是有一个服务的响应时间,每隔一段不固定周期就会出现一个尖刺,似乎也没有影响用户。但经过排查后,发现该服务会在一些特殊情况下调用某第三方服务,用作补偿数据,这次额外的调用会引发响应时间的增加。
<img src="https://static001.geekbang.org/resource/image/b9/c5/b9286eccc1c375ebfb074b9681208dc5.jpeg" alt=""><br>
这个逻辑本身其实没有什么问题,但隐患在于,服务与第三方调用是有配额限制的,但超出配额后没有兜底措施,一旦这种特殊场景增多,甚至遇到外部攻击,服务容量立刻就会雪崩。
因此,当你遇到容量指标抖动的情况,尤其是一些莫名其妙的抖动,不要忽视它,尽可能找到根因。如果服务内部排查不出问题,不妨检查一下有没有第三方同步调用,或者底层的基础设施和中间件有无问题。对于那些实在无法确定根因的抖动(在复杂微服务体系下,总会有那么些悬案),要加强监控,并制定故障恢复预案,以防出现容量问题时手忙脚乱。
## 总结
在安全领域有一个著名的法则叫海恩法则它告诉我们每一起严重事故的背后必然有29次轻微事故和300起未遂先兆以及1000起事故隐患事故的发生是量的积累的结果。海恩法则其实最终是想表达任何不安全事故都是可以预防的。就像我们上面提到的5个经典问题在容量保障领域任何不安全事故也是可以预防的你都学会了吗
首先容量指标分析不能仅关注单一指标无论是响应时间还是CPU利用率单个指标的优劣并不一定能完全说明问题需要联动去看。从实践角度建立监控大盘去汇总多个关联性指标是一个不错的做法。
其次做容量测试时如遇压不上去的情况应及时关注施压端的资源消耗程度CPU利用率和带宽是常见的会影响施压能力的指标我们同样可以通过监控告警的方式自动暴露问题减少人工判断的成本。
最后,我们不要轻易放过抖动情况,即便目前为止对系统功能没有影响,也要重视。抖动可以先从服务内部进行排查,看一下是不是有性能问题或是调用不合理之处,之后可以继续排查第三方同步调用和基础设施的问题,哪怕最终无法查到根因,我们也要制定预案,预防风险。
容量指标分析作为实践性极强的内容,所有这些知识点都需要你在实践中反复推敲和感受,方能融会贯通,正所谓神枪手都是子弹喂出来的,我只能帮助你少走弯路,但无法给到捷径。希望你能不断总结不断思考,形成属于你自己的容量指标分析最佳实践。
## 课后讨论
你在容量指标的分析过程中有遇到过我上面提到的,或者没有提到的困惑吗?如何解决的?如果你有一些自己的经验,也欢迎给我留言,我们一起交流。如果你觉得这一讲对你有帮助的话,欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,118 @@
<audio id="audio" title="04 | 容量治理的三板斧:扩容、限流与降级" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/a4/af/a4fd40909a3490ec3cc08ef2d4767eaf.mp3"></audio>
你好,我是吴骏龙。
在前面几讲中,我谈到了容量测试和容量指标分析等工作,这些工作能够帮助你验证服务是否存在容量问题,并定位问题出现的原因。
找到问题以后,我们需要排除这些容量风险,确保服务的稳定性,这就是容量治理需要做的工作了。优秀的容量治理工作不仅仅能**通过一系列手段解决已出现的容量问题,而且还能预防容量隐患,做到防患于未然。**
下面,我们就来认识一下三个常见的容量治理手段:扩容、限流和降级,这三个手段分别基于不同的视角,在容量保障中发挥着各自的价值。在这些内容的讲解中,我会从我经历过的实际案例出发,告诉你一些实践中的难点和坑点,希望能带给你更多的收获。
## 扩容的实践要点
说到扩容,不得不提到在软件架构设计中经常出现的一个词,叫做“伸缩性”,更高端的说法叫“弹性”。以目前互联网服务的用户体量,已经不太可能通过单台服务器去支撑所有的流量,流行的做法是将多台服务器组成集群统一对外提供服务,伸缩性指的就是能够往这个集群中不断加入新的服务器资源,以应对流量增长的能力,而这个**加入新的服务器的过程,就是扩容**。
如果容量瓶颈发生在服务器资源层面,扩容恐怕是最直接也是最“暴力”的容量提升手段了,尤其是在服务容器化盛行的当下,拉起一个新服务实例,往往只需要秒级时间,扩容的成本得到了有效的降低,能够快速消除容量风险。
我对扩容的态度是:**鼓励将快速扩容作为应急手段,但作为容量治理手段要谨慎,警惕无脑扩容和滥用扩容。**
在实际工作中很多业务研发一遇到自己的服务容量不足第一个念头就是扩容服务本身的优化工作包括异步处理、读写分离、增加缓存、SQL调优等等往往会被忽略这是有很大风险的。
首先,在开篇词中我就提到过,容量保障是要考虑成本的,如果纯粹依靠扩容去支撑性能低劣的服务,浪费的是大量的资源和金钱。其次,扩容也很容易触碰到边际递减效应,也就是说,服务资源达到一定规模后,再往上扩容的代价会大幅上升。
我在阿里本地生活推动容量风险改进时,说的最多的一句话就是:“不要无脑扩容!”。甚至每到大促活动期间,我都会与全局架构师进行合作,如果有业务方提交的扩容工单中仅仅提到了对扩容资源的需求,而没有考虑任何服务层面的性能优化措施,这样的工单会被直接拒绝。建立谨慎扩容的风气相当重要,如果大量的容量问题都靠“堆机器”去冲摊,服务资源的成本会越来越高。
除了避免无脑扩容,我还要提醒你注意的是,**扩容不能只关注服务本身的资源占用情况,还应同时关注对底层资源的影响**,如:数据库资源、中间件资源等。
举个简单的例子某服务集群一共有10个容器实例每个实例会建立约100个数据库连接加起来就是约1000个连接假设数据库总共支持的连接数为1200个这是能够支撑现状的。但如果考虑到近期业务增长较快会导致服务负载较大需要扩容5个实例那么总的数据库连接数大约会达到1500个这就肯定支撑不住的所以对服务进行扩容时对数据库也需要同步扩容。
再分享一个稍复杂的例子,在微服务体系中有一项服务发现机制,每个服务可以通过该机制获取被调用服务的位置。服务发现机制的一种实现方式是,由一个注册中心建立对每个服务实例的长连接,并维护一个服务状态列表,这样一旦服务状态发生变化,注册中心能够第一时间感知到并对服务状态列表进行更新。
我们很容易想到,这些建立的大量长连接可能会产生瓶颈(主要是消耗内存),当我们对服务进行扩容时,实际上就是增加了服务实例,这会产生更多的长连接。因此在这种服务发现模式下进行扩容时,注册中心的容量也需要同步考虑。
如果你觉得扩容要考虑的点太多,一种通用的做法是,先梳理出被扩容服务的调用链路,看一看流量经过哪些地方,分析一下这些地方会不会受到扩容的影响,再去采取相应措施。
总结一下扩容的实践要点,首先,要建立**服务性能优化胜过简单扩容**的意识,努力通过性能优化腾出容量,避免不经思考直接扩容。其次,扩容要联动系统整体资源共同规划,不能只关注服务资源。
## 限流的实践要点
扩容的出发点是尽可能提供足够的资源保证服务容量充足,但正如我在第一讲中所提到的,容量保障是需要兼顾成本的,限流就是**在<strong><strong>控制成本的情况下对**</strong>服务容量的一种保护措施</strong>。此外,即便进行了严密的容量规划和系统优化,我们依然无法保证线上流量一定百分百符合既定的预测范围,因为总会有这样那样的突发事件发生,如果流量峰值超过了系统能够承载的极限,相较于紧急扩容,**提前设置合理的<strong><strong>限流对系统进行过载保护**</strong>,是更主动的方式</strong>
那么,在提前设置限流时,我们应该选择什么样的限流策略,以及在什么位置进行限流呢?下面,我就从限流策略和限流位置两个角度,告诉你在选择策略和位置时应该注意的要点。
首先,从限流策略的角度,可以将常见的策略形象地归纳为“两窗两桶”,分别有:固定窗口、滑动窗口、漏桶算法和令牌桶算法。这些策略本身的实现方式和特点我就不多费笔墨了,网上已经有很好的学习资料,你可以[点击](https://xie.infoq.cn/article/32606ec229eb96f3bb4b295ee)查看。我会将讲解的重点放在如何选择合适的限流策略,以及如何建设有层次的限流体系上。
首先要与你分享的经验是,**限流策略的选择和业务场景应当是高度挂钩的**,不能想当然觉得复杂的策略就一定好。为了让你更深刻的理解这一点,我总结了上述四个限流策略中,与业务场景紧密相关的三大流量控制方式,分别是:流量整形、容忍突发流量和平滑限流,它们的含义如下:
- **流量整形:** 指不管流量到达的速率多么不稳定,在接收流量后,都将其匀速输出的过程,即“乱进齐出”。
- **容忍突发流量:** 指的是限流策略允许流量在短时间内突增,且在突增结束后不会影响后续流量的正常限流。
- **平滑限流:** 指的是在限流周期内流量分布均匀比如限制10秒内请求次数不超过1000平滑限流应做到分摊到每秒不超过100次请求。反之不平滑限流有可能在第1秒就请求了1000次后面9秒无法再发出任何请求。
基于这三个特点,结合不同限流策略对流量控制方式的具体支持情况,我汇总出了下面这张表格。
<img src="https://static001.geekbang.org/resource/image/3d/9e/3d99dfa94e13885dd0c9594060052f9e.png" alt="">
有了这张表格,你就可以根据业务场景去选择合适的限流策略了。比如说,固定窗口无法容忍突发流量,但它实现简单,资源消耗少,如果你的应用服务流量是平缓增长的形态,也没有流量整形的需求,这时采用固定窗口策略进行限流就不失为一种合理又经济的选择。
相反,如果你的应用服务经常需要应对诸如大促场景这样的突发流量,那么使用令牌桶算法进行限流往往会更适合,当然,这时你也得接受令牌桶策略实现的高复杂度。
总之,针对每个限流策略的特点,在具体业务场景合理使用,才能发挥它最大的价值。
好了,聊完了限流策略,接下来我们将视线切换到另一个维度,从限流位置的视角来探讨限流实践,这里想说明的核心理念是:**良好的限流应该是分层次的**。这就好比我国长江的防洪策略,有三峡这个“巨无霸”在上游作为挡板调控洪峰,下游有葛洲坝、溪洛渡这样的中型水电站进一步调节水量,再往下还有无数小型水库进行精细化控流,形成了全方位保护的机制。限流也是同样的道理。
根据不同的限流位置,限流可以划分为**网关层限流、接入层限流、应用层限流、数据库层限流等**。我们直接来看下面这张图,图中自上而下描述了服务的流量走向,非常清晰地体现出层次化的限流思路,每个位置都恰如其分地加入了相应的限流策略,下面我具体解读一下。
- 第一层入口网关可以针对域名或IP进行粗放式限流静态资源直接走CDN内容分发网络同时在这一层还可以将一些不合法的请求拦截掉不要流入下游仅放过合法请求。
- 第二层,硬负载和接入层都可以实施负载均衡和限流措施,分担服务压力。它的粒度比入口网关层更细,但还没有办法对单个服务实例进行限流。
- 第三层,到了应用服务层,每个服务可以有自己的单机或集群限流,调用第三方服务时,也可以单独进行限流。
- 第四层,与数据库的交互,采用读写分离的方式,分流数据库压力,同时也可以针对数据库读写请求进行限流。
<img src="https://static001.geekbang.org/resource/image/b5/75/b534ba005f715b7d38d7ded2334ce975.png" alt="">
总之,在制定每一层的限流策略时,**都应该抱着不信任上层限流的思维**,这样即便某一层限流机制发生问题,也不至于引发全局问题,最终形成的限流体系才是最健壮、最可靠的。
总结一下,限流的核心思路是:第一,根据业务特点,比如是否有突发流量、输出流量,是否需要整形、是否需要平滑限流等,选择合适的限流策略,确保限流策略的健壮性和可靠性;第二,分层次,在不同的位置进行限流,多管齐下全方位完善限流体系。
## 降级的实践要点
前面提到的限流措施,是通过拒绝一部分服务流量来强行控制服务负载的手段,是从控制流量的视角来保证服务容量安全的;而降级则是从系统功能角度出发,**人为或自动地将某些不重要的功能停掉或者简化,以降低服务负载,这部分释放的资源可以去支撑更核心的功能**。简而言之,弃卒保帅。
降级在互联网行业的应用非常广泛比如某大型电商在双11当天会将退货的功能降级以确保核心交易链路的容量充足某生鲜公司在遇到流量高峰期时会将一部分个性化推荐的功能降级以确保导购链路的工作正常等等。抽象总结可以有以下几类策略我同时提供了一些案例供你直观地理解它们。
<img src="https://static001.geekbang.org/resource/image/82/c5/827d29736c46e0d3c74eb895790a74c5.png" alt="">
降级的技术实现本质上不难,也是微服务系统的常见功能,绝大多数情况下,是通过设置开关,并将开关收口至配置中心的方式作集中式管理的。我想深入讲解的知识点是,如果你已经有了一套降级系统,该如何管理上面的众多降级开关,把它们真正有效地推行下去,在服务容量发生风险时,及时止损,或提前止损。
首先,降级需要平衡好自动触发和人工执行两种做法。根据预置的触发条件自动执行降级固然快速便捷,但某些场景的降级触发条件其实挺难判断的,比如在系统偶发抖动的情况下,到底是降还是不降,需要根据当时的业务情况做综合判断,这时候还是人工介入更靠谱。此外,还有一些降级会涉及到与第三方的合约,比如对支付宝、微信支付这类功能的降级,需要与对方确认后才能执行。
自动降级比较适合触发条件明确可控的场景,比如请求调用失败次数大于一定的阈值,或是服务接口超时等情况;还有一些旁路服务,比如审查日志记录等,如果压力过大也可以直接触发自动降级。我将这些要点总结为下面这张导图,供你参考。
<img src="https://static001.geekbang.org/resource/image/52/96/521834078ec83ec649047278afd89096.png" alt="">
其次,降级需要进行分级,因为降级操作都是有损的(如果无损,那你应该考虑一下被降级的功能是否还有存在的必要了),所以如果进行“温柔的”降级已经能够释放足够的容量,就没有必要过度降级。
基于这个理念我们可以根据对业务的影响程度制定降级的分级策略。比如在导购链路上针对个性化推荐和滚动热词功能的降级就属于不太影响用户使用的范畴可以定为1级降级而不展示商品图片和评价内容这类降级明显会对用户使用造成不便应定为2级降级。在真实发生容量问题时可以先执行1级降级如果服务恢复则无需执行2级降级。
最后,降级需要演练,而且是频繁的演练。有些服务的降级逻辑由来已久,随着服务代码的迭代更新,这些降级逻辑可能已经失效了,一旦服务出现问题真要降级时,这可是要命的。通过高频演练可以及时暴露这些无效的降级开关,防患于未然。
总结一下,**降级与限流有明显的区别,前者依靠牺牲一部分功能或体验保住容量,而后者则是依靠牺牲一部分流量来保住容量。** 一般来说,限流的通用性会更强一些,因为每个服务理论上都可以设置限流,但并不是每个服务都能降级,比如交易服务和库存服务,就不可能被降级(没有这两个服务,用户都没法购物了)。
降级的策略还是比较丰富的,因此需要从多个角度去化简。首先,将一部分判断条件简单的降级通过自动化手段去实现;其次,根据对业务的影响程度,对降级进行分级,达到有层次的降级效果;最后,通过高频演练,确保降级的有效性。
## 总结
这一讲,我主要介绍了容量治理的三个手段:扩容、限流和降级,将容量测试获得的数据和分析工作的价值真正落到实处,降低容量风险。
实际工作中,需要特别警惕无脑扩容,加强服务架构优化意识和根因分析能力;在扩容时,也应全面评估系统资源情况,做到资源平衡。
奥卡姆剃刀定律告诉我们:“如无必要,勿增实体”,简单的才是最有效的。限流策略的制定应充分考虑业务场景特征,选择最简单和最适合的限流策略,而不是盲目追求复杂的策略。同时,限流应当从全局视角看待,建立层次丰富可靠的限流体系。
降级的本质是为了解决服务资源不足和访问量增加的矛盾,而放弃一部分功能或体验。降级应当平衡好自动化降级和人工降级的关系,并通过分级的方式保证最小可用降级,最后辅以大量高频的验证,确保降级的有效性和熟练度。
容量保障,任重道远。没有无死角的容量治理手段,我们应当全方位、体系化地思考认识,多角度覆盖容量保障的方方面面。
## 课后讨论
现在有这样一个业务场景它的主要工作是审阅、处理和发放工资。我们有一个服务系统支撑这个业务场景其中审阅和处理工资是由公司财务在系统上完成的在每月的最后一周是高峰期其他时间几乎没有请求而发放工资的功能是对接银行的第三方接口实现的这个接口非常脆弱每秒只能处理5个请求。
请问,针对这样的一个服务系统,选取哪种限流策略比较合适?欢迎与我交流你的想法,在评论区给我留言。如果你觉得这一讲对你有帮助的话,欢迎把它分享给你的朋友。

View File

@@ -0,0 +1,91 @@
<audio id="audio" title="开篇词 | 互联网时代,人人肩负容量保障的职责" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/yy/16/yy660bbc72f02b862d97873f49f87116.mp3"></audio>
你好,我是吴骏龙。欢迎你和我一起学习容量保障。
如果你现在还不知道“容量保障”到底是啥意思那也不用着急。因为容量保障其实就在你我身边。我们在使用的各种互联网应用比如你点外卖使用的“饿了么”“美团外卖”等等比如你使用的各种电商App它们的稳定运行背后靠的都是各类技术保障工作。
而在这些技术保障工作中,最重要的就是质量保障和容量保障这两类:
- 质量保障,是确保服务功能正确,不出问题。比如,订单系统结算时,要保证金额正确。
- 容量保障是要保证服务在大量用户访问时依然可以正常工作。比如在“双11”购物节的超高访问量下各电商网站依然能够稳定地运行。
而我先后在eBay上海研发中心和阿里巴巴本地生活前身是“饿了么”工作近8年的时间做的就是质量保障和容量保障相关的工作。
在eBay工作时我主要负责质量保障工作在部门内建立了完善的自动化测试体系和持续集成流水线并将机器学习引入到软件测试工作中解决了测试报告自动分析的难题。这些成果至今仍然是互联网行业的前沿研究方向。
后来我到了阿里本地生活当时恰逢异地多活项目落地随之而来的是全链路压测工作的启动。作为当时团队中的平台开发Leader我有幸参与了这项浩大的工程并主导负责了整个全链路压测的自动化和规范化工作。这是我第一次系统接触容量保障工作的重要环节它就像是我的孩子一样成长。直到现在我们曾经的团队成员聚首对此还会津津乐道。
在全链路压测走向正轨以后,我渐渐发现仅通过全链路压测是无法全面保障系统容量安全的。于是,我将工作重点从全链路压测这个专项,转向了整个容量保障的体系化建设,致力于推动高效和富有层次的容量保障实践,并带队攻克了多项容量预测难题。我自己也作为阿里本地生活的全局容量保障负责人,固守着这一片碧海蓝天。
目前,我在一家创业公司继续我的质量保障和容量保障事业,而容量保障是我深耕最多的领域,也是我投入巨大热情的地方。
那为什么我想要开设这样一门课呢?
在我的职业生涯中能够非常深刻地感受到容量保障对于一家互联网公司的重要性因为几乎每时每刻我都在回答这些问题我负责的软件系统目前运行的很好但是公司业务增长迅猛如果访问量增加2倍系统还能支撑吗如果无法支撑2倍的访问量哪些服务会首先成为瓶颈这些服务如果采取扩容措施需要扩容多少量大规模促销活动场景下容量风险如何识别和预防
与此同时,随着互联网应用复杂度和系统架构复杂度的不断增加,容量保障涉及的工作越来越多,随之而来的误区和困惑也越来越多。
我在多个场合进行容量保障分享时,也经常被问及这样的问题:
- 我们一直在做性能测试,为啥服务容量还是老出问题?
- 容量保障,有没有套路可循?
- 我们公司规模不大,没有专人去做容量保障,有没有成本低点的办法?
- 我公司规模不大,业务也没有什么大促场景,需要做容量保障吗?
别着急,这个专栏我们就是来解决上面的问题。我写这个专栏的最大初衷,也是希望把我在容量保障领域的经验,总结成方法论分享给你,帮助构建一个全局视角,使你**不仅知道容量保障该怎么做,还能深入理解为什么要这样做。**
在互联网行业飞速发展的今天,除非我们的系统有非常固定的用户规模和长期不变的业务逻辑,否则,**容量保障应当是每个互联网公司都需要广泛关注的工作**。无论你是性能测试人员、研发人员、架构师、运维人员或是现在流行的DevOps或SRE人员都应当具备容量保障技能重视容量保障工作。
看到这里,你是否会有困惑,性能测试、压测、扩容……这些词就代表容量保障吗?容量保障到底是什么呢?在这里,我就给你下个定义吧。
## 到底什么是容量保障
我们拆开来看,**容量保障=容量+保障**。
容量是什么?容量是一个在生活中很常见的概念,我们喝水的杯子就有容量,我们每天上班搭载的地铁也有容量。广义的容量可以定义为:容器能够承载物质的量。杯子就是容器,水就是物质,杯子能够装多少水就是容量。
而从互联网技术视角出发,我们可以将软件系统或服务视为容器,流量或业务量视为物质,那么就可以得到互联网软件系统容量的概念,即“单位时间内软件系统能够承载的最大业务量”。
<img src="https://static001.geekbang.org/resource/image/11/de/1171b3aef0b54af7d5aedd9ayyfe12de.jpeg" alt="">
而**容量保障,就是用各种方法保证软件系统的容量充足,预防容量隐患的重要工作。**
容量保障对于系统稳定性至关重要如果一辆货车核载80吨而我们塞进了100吨的货物后果可想而知。互联网历史上多家大厂也曾发生过多次因容量问题引发的线上事故比如某年春晚某头部电商的摇一摇红包活动短暂宕机微博在娱乐圈出现热门事件时的频繁宕机都对用户造成了巨大影响。以至于网友纷纷调侃衡量明星火不火就看微博是否为他/她宕机过。
## 容量保障难不难?
也许你会问,既然容量就是系统能承载的业务量,那我多加点服务器不就行了吗?但我要告诉你,容量保障不是这么简单的,否则就不会有上面那么多困惑了。
互联网场景下的容量保障工作是一项系统性工程,它的难点主要体现在以下几个方面。
**1. 容量的不确定性:** 一辆货车在交付时已经标注了核载重量,而互联网服务的容量受服务器资源、架构设计、网络传输状况和业务场景等多种条件制约,会呈现出不同的容量表现,很难得到确定解。
**2. 容量评估的复杂性:** 随着微服务架构的日益盛行,服务链路变得越来越复杂,任何一个环节出现容量瓶颈都有可能放大到整条链路,这给容量评估工作带来了难度。
**3. 容量测试的不准确性:** 容量测试的场景需要尽可能逼近真实情况,还需要保证被测服务的环境(服务资源、规模、配置等)与真实环境对等,但实际上受制于各种原因,我们很难做到完全仿真,因此容量测量的准确性也是一个挑战。
此外,容量保障还会牵扯到成本管理的问题,这也是一个难点。因为工程师主要面对的是技术问题,更关注技术层面的目标,而公司的管理层则倾向于将项目成果和业务需求作为核心目标。在实际业务发展过程中,尤其是在业务进攻期,系统所需资源比如:服务器、内存、硬盘、网络带宽等,它们的成本很容易被工程师们忽略,或者在很晚才被考虑。
从全局来看,如果前期对研发资源成本缺乏规划,等到业务发展到了一定规模,拿到机器账单的时候,惊呼“机器怎么这么费钱”,再想立即降低成本,可能已经错过了最佳时机,因为技术改造本身是一个相对长期的过程。很多公司的成本管理意识可能就如下图所示,是不健康的。
<img src="https://static001.geekbang.org/resource/image/b9/90/b99cc9cfeaefd47b9cf08e5be3678c90.png" alt="">
因此,容量规划是容量保障的一个核心环节和难点,不仅要保证服务能够承载相应的流量,还要确保以尽可能少的资源来承载这些流量;更进一步的,在当今开源节流的大背景下,我们还希望以尽可能低的人力成本,保障容量安全。
说了那么多难点,那么如何将它们变得不难呢?这就是我的这个专栏希望带给你的价值。
## 课程是如何设计的
在这次的专栏中,我将从技术视角出发构建一个容量保障体系化的大图,覆盖容量保障工作的方方面面,逐个击破,尽可能全面地展现容量保障各项技术的全貌。具体来说,会有以下三个部分。
- **基础篇:** 我将以容量保障工作的时间轴为主线,分别就目标、测量、分析、治理这几大工作展开,积累容量保障的通用方法,帮助你完成基础入门。
- **进阶篇:** 我将分几个独立专项话题对容量保障工作中的一些前沿技术进行深入剖析包括全链路压测、分布式压测平台的研发工作以及AI预测容量、云原生下的容量保障新趋势等。**这其中部分话题在业界甚至是<strong><strong>第一**</strong>次公开</strong>,非常值得学习。
- **案例篇:** 从案例场景出发介绍双11大促场景下的容量保障工作如何做好及小公司如何建立容量保障体系并对容量保障组织建设给出我的建议。
在这里,我先为你总结一套较为适合互联网场景的容量保障方法论,如下图所示。先从“日常容量”和“大促容量”的目标出发,拆分出三个入口,分别对应计划事件(事先能够预知的新功能或大促活动)、突发事件(事先无法预知的紧急事件)和日常事件(常态化的容量表现)。再自上而下拆解出具体的策略(工作项、工具、规范、案例等),每一项策略再做具体细分,形成一个有机的整体。
<img src="https://static001.geekbang.org/resource/image/5b/7d/5bf22a0a47071ab80def7e88f4e3f67d.png" alt="">
在接下来的讲解中,我会再对这个方法论体系中的核心环节进行详细描述,帮助你更好地理解和落地。当然,这套方法论未必适合所有的场景和业务形态,但我认为,即便是在一个全新的领域,它也可以帮助你在最短的时间内,建立一套有效的容量保障体系。**更重要的是,它提供了一种核心的思维方式**。
最后,我想跟你分享一句我很喜欢的名言,来自列宁:“我们不需要死读硬记,我们需要用基本的知识来发展和增进每个学习者的思考力”。希望这个专栏能够引发你的思考,助你早日成为一名容量保障的“尖兵”。

View File

@@ -0,0 +1,122 @@
<audio id="audio" title="05 | 全链路压测:系统整体容量保障的“核武器”(上)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e3/c3/e3a206024ba38726007fb739652a38c3.mp3"></audio>
你好,我是吴骏龙。
通过基础篇的学习相信你对容量保障的相关知识已经有了基础的了解知道了容量测试不能简单定义为压力测试而是验证服务容量的手段知道了容量指标分析不能只看单一指标也学习了分析容量指标的5个经典问题以及了解了容量治理可以采取扩容、限流和降级策略。
从今天开始,我们踏入进阶篇,进阶篇的所有内容都是比较前沿或创新的知识,希望通过大厂前沿经验和我的积累,帮你拓宽视角。在进阶篇,我们从关注度最高的全链路压测开始,与你分享我的实践经验。
你可能会问,到底什么是全链路压测?实施全链路压测要经过几个步骤?有哪些难点坑点?别急,因为内容较多,我会分成两讲,这一讲,先聊聊全链路压测的诞生,以及实施全链路压测前的三项改造工作。下一讲,我们再进一步聊聊两项具体的压测工作,把全链路压测的建设过程完整展示给你。
## 全链路压测的诞生
2013年对阿里巴巴来说有着非凡的意义因为那一年全链路压测诞生了。这可是双11容量保障工作的福音对守在电脑前的程序员们来说流量洪峰终于不再那么可怕了。
虽然当时我还没有进入阿里体系内工作但我作为一名用户亲身参与了从2011年开始的所有双11活动我能深刻感受到双11系统稳定性的变迁。总体来说2011年和2012年给我的体验不太好但2013年就有了很大的改观。
2011年和2012年双11活动的整点系统不可用的问题对我造成了很大的困扰访问网页各种报错连付款都困难当时把我给着急的呀生怕要买的东西被抢完了如果你也经历过那时候的双11应该能够感同身受。
不过从2013年开始虽然每年双11的规模都在大幅增长但除了付款操作偶尔还会被限流以外网页无法访问这种系统不可用的情况几乎碰不到了。直到后来我进入阿里体系内工作后才知道当时的阿里人为此付出了大量的努力和汗水在短短几个月的时间内大刀阔斧地推动各项改造构建压测模型创造性地完成了全链路压测的建设工作才得以保证双11的稳定进行。要知道当年双11的流量峰值已经超过了每秒4万笔交易量放眼全世界也是独树一帜的存在。
阿里的经验证明了一点,那就是对未来可能产生的流量峰值而言,任何预防性的稳定性保障手段,都不如**把实际峰值场景模拟出来“看一看”** 来的有效,这就好比建造三峡大坝,预计能抵挡千年一遇的洪水,但是否能达到这个目标,还是需要经历多次洪水考验才能证明的。全链路压测就是通过模拟这场千年一遇的洪水,来验证服务系统是否能承载预估的流量峰值。
在全链路压测诞生前阿里双11的容量保障工作主要是对业务目标进行拆分对各个服务链路单独进行压测虽然也进行了大量的压测工作但实际发生流量洪峰的时候很多系统的容量还是会有问题。
为什么单链路压测无法排除系统整体容量风险呢,因为整体系统的容量不是由多条“单链路”的容量简单相加而得的。我们看一下下面这张图,它表达的含义是,应用服务的容量除了受自身影响,还受依赖服务的影响,而依赖服务又可能有其他调用方,甚至是一些外部服务,这些影响经过几层累积后,最终的影响面极难判断。
<img src="https://static001.geekbang.org/resource/image/d2/a8/d2055a04f72b5fd8f5248b973144e9a8.png" alt="">
而全链路压测直接从全局视角出发,它的本质是基于线上真实环境和实际业务场景,通过模拟海量的用户请求,来对整个系统的容量进行评估的手段。当然,罗马不是一天建成的,全链路压测也不是一蹴而就的,有很多重点问题需要解决,我们可以从两方面思考。
首先,全链路压测本质上也是一种容量测试的手段,因此容量测试需要解决的问题也是全链路压测面对的重点问题,比如**数据隔离、压测场景置信度、对正常业务的影响**等,其中有些内容我在之前的讲解中也已经涉及到了。
其次,全链路压测的特点决定了它会存在一些独有的重点问题,由于全链路压测遵循与用户访问相同的流量轨迹,因此会涉及大量的服务链路,我们需要保证**压测流量在这些链路中流动时的完整性和可识别性**。此外,有别于单链路压测只需要制造局部流量,全链路压测需要**制造大规模的整体流量**,这也是需要重点考虑的。
<img src="https://static001.geekbang.org/resource/image/77/2a/778a235998568e2754300b804915432a.png" alt="">
可以说,解决了上面这些问题,就具备了全链路压测实施的基本条件,下面我就来具体展开讲解一下全链路压测的建设过程,其中包含三项改造工作和两项压测工作。
三项改造工作包括:数据隔离、中间件改造和应用服务改造,这些改造工作致力于解决上面提到的压测流量的完整性和可识别性、数据隔离以及对正常业务的影响这些重点问题。而两项压测工作则包括:压测模型构建和压测流量构造,对应上面提到的场景置信度和大规模流量制造这两个重点问题。关于两项压测工作,我们下一讲展开。
## 全链路压测应该如何建设
### 三项改造之数据隔离
为了避免环境不对等所造成的压测结果失真,全链路压测一般都是在生产环境展开,而线上压测就一定会涉及到数据隔离的问题,压测数据需要与真实数据有所区分,确保不影响真实用户的体验。因此,数据隔离是全链路压测建设过程中最重要,也是最必不可少的工作。
常见的数据隔离方式有两种,分别是:**逻辑隔离**和**物理隔离**。
逻辑隔离是指通过数据打标的方式区分真实数据和压测数据,在各实体(如用户、商户、订单等)中添加压测类型标识。比如针对用户这个实体,可以设置一个用户类型字段,其他系统或服务可以根据这个字段硬编码走相应的隔离逻辑。
```
enum UserType {
NORMAL = 0, # 普通用户
PERF = 1, # 压测用户
}
```
逻辑隔离实现简单容易理解但难以标准化因为具体的字段设置是由业务技术方决定的。比如上面举例的用户数据中的压测标识字段是UserType但商户数据中的压测标识字段可能就变成了ShopType上游系统如果需要同时识别多种数据的压测标识时会比较困扰。
第二种数据隔离方式是物理隔离,它的做法是先通过在压测流量中进行打标的方式,区分真实请求和压测请求,再将压测请求所涉及的数据存储到另一个与真实表数据结构对等的表中(俗称影子表),使压测数据在物理上与真实数据隔离。这就涉及两个重点工作,一是在压测流量中打标,二是建立影子表。
在压测流量中进行打标该如何做呢通常情况下流量入口大多是HTTP请求压测流量标识可以置于HTTP Header中进入内网后相关中间件需要将HTTP Header中的压测流量标识转移至内部请求如RPC请求的上下文中如遇异步组件如消息队列也需要做特殊处理具体我会在下文“中间件改造”那部分展开。
这个过程要确保压测流量标识能够一路透传(传输过程中不对标识进行改变)至数据层不丢失;最后,数据层,如数据库中间件通过对压测流量标识的识别,将数据写入影子表,完成整个物理隔离的全过程。
<img src="https://static001.geekbang.org/resource/image/72/f2/72cfee8ec07f4dbf683374b904053cf2.png" alt="">
值得一提的是,物理隔离还有一个额外的好处,由于实现物理隔离必须构建统一的压测流量标识,那么分布式链路跟踪系统也可以根据该标识,直观地展示压测链路,这样比较方便监控和排查问题。
那么,影子表如何建立呢?为了使全链路压测对于数据库容量的评估准确,我们需要保证影子表的数据内容和规模与真实表一致,但又不能与真实表数据冲突,你可以参考以下过程建立影子表:
1. 针对某张真实表建立相应的影子表表名可以通过增加前缀或后缀区分比如原表名为User影子表名可以设定为User_T其他影子表也都基于_T这个后缀建立。
1. 将真实表的数据进行脱敏部分id类字段需要进行偏移以免增长后与真实表冲突比如真实的订单号都是以1开头那么影子表中的订单号可以偏移为以9开头。
1. 脱敏和偏移后的数据导入到影子表中。
1. 进行完整性检查(数据量、表结构等内容),确保数据无误。
<img src="https://static001.geekbang.org/resource/image/eb/9d/ebde00beee2b58e6432879374084289d.png" alt=""><br>
逻辑隔离和物理隔离各有千秋,两者对比如下表所示。我的经验是,如果你公司的技术体系比较成熟,技术栈统一,也有固定的中间件团队支持,那么可以尝试使用影子表的方式进行数据的物理隔离;反之,如果技术体系不完整,或大量使用开源框架,二次开发成本高,那么可以采用逻辑隔离的方式。
<img src="https://static001.geekbang.org/resource/image/04/d7/0436754c1fe1120be566e056f6b403d7.png" alt="">
### 三项改造之中间件改造
在数据隔离环节我已经提到,压测流量标识透传以及数据的物理隔离等工作,都需要对中间件进行改造,比较典型的有数据库中间件对影子表的支持,消息队列对压测流量标识传递的支持,等等。
数据库中间件对影子表的支持比较简单,上面也已经提到过,实现的机制是基于压测流量标识,数据库中间件接收到某个带有压测流量标识的请求需要操作数据库时,将这个操作的目的地重定向到影子表上。这些影子表的信息,以及与真实表的映射关系,可以维护在一个统一的地方做管控,同时供数据库中间件调用。
另外一个典型的中间件,消息队列,它是微服务体系中常见的中间件。消息队列对压测流量标识传递的支持,主要目标是保证在生产和消费数据时,压测流量标识不能丢失。具体来说,当有压测请求作为生产者将数据写入消息队列后,这个生产者的使命就完成了,当消费者去消息队列中消费出这条消息时(相当于另一次请求),我们已经无从知晓数据是压测数据还是真实数据了,这破坏了压测流量的可识别性。
因此,对消息队列需要进行改造,当接收到带有压测请求标识的生产者推送消息时,需要将压测标识转存至数据中,以免丢失,当异步服务消费数据时,再将该标识恢复至请求体或上下文中继续传递。
<img src="https://static001.geekbang.org/resource/image/ec/cb/ec041061c9e891607f2c28784e0bd6cb.png" alt="">
通过以上两个例子,你可能也发现了,中间件需要改造的地方基本上都是**与压测数据打交道**的地方,所以在中间件改造方案的制定中,我们需要对数据特别敏感,涉及到数据的地方可能都是潜在的改造点。
### 三项改造之应用服务改造
除了中间件改造,应用服务也需要进行一定的改造,确保压测请求能被反复执行,并且不影响真实场景,常见的应用服务改造点有:
- **绕开限制逻辑:** 比如系统针对短时间内反复下单的用户将进行限制,这个逻辑针对压测流量需要放开。
- **数据隔离前置:** 数据隔离前置能够减轻其他应用服务改造的工作量,比如大数据报表中需要对压测数据进行剔除,如果这些报表的数据源都在数据仓库里,那么我们完全可以在压测数据生成时就隔离掉不进数据仓库,这样大数据服务就无需改造了。
- **Mock逻辑** 有些对外交互的服务是不太方便发起大量真实请求的比如支付和清结算等这些功能可以在识别到压测流量后走Mock服务也就是模拟一个正常的返回而不是直接调用真实服务。
除此之外还有一些如风控拦截等安全性方面的限制也需要适当放开以便压测请求能够重复执行。总之所有可能会限制或阻碍压测请求流动的地方都需要打通如果无法打通那就Mock。
好了,到这里,数据隔离、中间件改造和应用服务改造都完成后,我们已经初步具备了实施全链路压测的条件。接下来就是压测实施层面的工作了。下一讲,我们主要来聊聊压测模型构建和压测流量构造两项工作。
## 总结
在这一讲中我首先与你分享了全链路压测的诞生过程正所谓“预见未来最好的方式就是实现未来”阿里通过将全链路压测成功应用于双11活动的保障工作证明了这一点也为容量保障带来了一个强大的武器。
全链路压测通过模拟海量的用户请求,来对整个系统的容量进行评估,其建设过程涉及到的要点还是比较多的,今天我们主要讲的是三项改造工作,这里面有几个重点你可以关注:
- 数据隔离是全链路压测建设过程中最重要的工作,逻辑隔离和物理隔离是两种常见的数据隔离方式。
- 如果公司的技术体系比较成熟,基础设施统一且有专业团队维护,那么可以尝试使用影子表进行数据的物理隔离,这样数据风险更小;反之,如果基础设施改造成本太大,就建议采用逻辑隔离的方式。
- 在中间件改造方案的制定中,我们需要对数据特别敏感,涉及到数据的地方可能都是潜在的改造点。
- 常见的应用服务改造点有绕开限制逻辑、数据隔离前置、Mock逻辑等这些改造工作能够确保压测请求的正常流动也能更好的配合数据隔离。
## 课后讨论
在中间件改造的版块中,我详细讲解了消息队列的改造工作。如果你要在公司内实施全链路压测,你觉得还有没有其他和数据打交道的中间件需要做改造的?如果有的话,你会怎么设计改造方案?欢迎你给我留言,也欢迎分享给更多的朋友一起阅读。

View File

@@ -0,0 +1,94 @@
<audio id="audio" title="06 | 全链路压测:系统整体容量保障的“核武器”(下)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d2/51/d2848e6d40f3fe6703a074f8c58ea151.mp3"></audio>
你好,我是吴骏龙。
上一讲,我为你讲解了在正式实施全链路压测前,我们要做的三项改造工作,包括数据隔离、中间件改造和应用服务改造。这一讲,我们就正式进入两项压测工作:压测模型构建和压测流量构造,把全链路压测的建设过程完整展示给你。除了技术工作之外,在这一讲中我还会与你分享全链路压测的组织协调和运营工作,它们对全链路压测的完整落地同样起到至关重要的作用。
我们先看看如何构建压测模型。
## 两项压测工作:压测模型构建
构建压测模型的重点是准确度,如果模型与真实场景相差过大,那么压测结果的可参考性将会大打折扣,下面是一些典型的由于压测模型不准确导致压测结果无效的反面教材:
- 下单链路中,压测用户没有使用红包,导致对营销服务的压测结果偏优。
- 压测用户数据未考虑sharding分布导致数据库单片过热。
- 压测用户数量过少,使用有限的压测用户反复下单后,导致单个用户订单量过多。
- 压测商户数量过少,压测时针对单个商户的操作过于密集,导致菜品扣减库存的锁争抢激烈。
压测模型包含业务模型和数据两部分,我再来通过几个实例讲解一下如何构建尽可能真实的场景。
**实例一: 读请求**
读请求由于不会对数据造成污染,因此可以直接使用真实请求和数据进行回放。
- 压测场景:商家列表及关键词查询。
- 业务模型:拉取线上日志,根据真实接口比例关系进行回放。
- 数据:拉取线上日志,使用真实数据。
**实例二: 写请求**
写请求一般需要单独构造压测模型,并做好数据隔离和清理工作。
- 压测场景:用户下单
- 业务模型根据生产监控或日志获取下单场景的链路信息观察接口调用情况和上下游依赖当然你也可以写一个系统帮你做这个事。产品、研发和测试共同评审链路的完整性。另外评估业务改造点比如需要对支付和短信等环节进行Mock。
- 数据:构建测试用户、测试商户、测试菜品等数据,数量上与线上真实情况等比例缩放;及时对压测数据进行清理,或使用影子表。
归纳一下,压测模型构建的核心要点是,要利用好生产环境的各种信息来帮助我们**构建贴近真实业务的压测模型**。生产环境是个聚宝盆,请求的依赖关系、调用比例、数据特征都是我们构建压测模型的素材,将这些数据抽取出来再进行精加工,即可得到贴合实际的压测模型。
## 两项压测工作:压测流量构造
有了压测模型和数据最后临门一脚就是构造压测流量进行施压。全链路压测对于压测流量构造的技术选型主要取决于流量的规模如果规模不大传统的压测工具是可以支持的如JMeter、Locust、nGrinder等如果是大规模流量乃至超大规模流量百万请求量级成本就会比较高。对于后者可以考虑自研一套压测平台这也是很多大厂的做法我在下一讲会专门展开这部分内容敬请关注。
我们来总结一下,全链路压测的建设过程可以归纳为两个重点:首先,通过中间件改造和应用服务改造,保证压测流量的完整性和可识别性,并保证压测数据与真实数据隔离开;其次,利用生产环境的各类信息,构建贴近真实场景的压测模型,并通过构造大规模压测流量实施全链路压测。
这些工作都完成后,全链路压测在技术层面的建设就基本告一段落了。
## 全链路压测的组织协调和运营工作
说了那么多,也许你会觉得建设全链路压测的技术难度还是挺高的,但我想告诉你的是,除了技术工作,组织协调和运营工作其实更难。这就好比新冠肺炎疫情的防控,全世界都知道中国的成功经验,但有几个国家能成功复制中国的防疫举措呢?
关于全链路压测建设时会涉及到的组织协调工作,通过全链路压测的建设过程相信你也看到了,其中光中间件改造和业务改造两项工作,就几乎覆盖了大半个技术团队,要同时协调那么多团队的工作安排,难度不小吧?
我认为,推动全链路压测这样的“航空母舰”项目,是需要自上而下的,但不一定非要强推。我在阿里本地生活工作时,技术团队建立了 **“Program机制”**这是一种针对跨团队大型项目的推动机制由CTO直接牵头和授权对公司内部需要推动的技术改造类项目进行必要性和优先级评定。
从项目跟进的角度来说所有公共团队如基础设施团队、大数据团队等和业务团队的技术Leader需要定期参加会议在会议上对这些项目的进展和风险进行讨论业务团队必须在约定时间内完成公共团队的技术改造需求而公共团队则需要提供合理的方案并提供足够的支持。
Program机制为基础设施团队推动技术改造类项目提供了一个强有力的抓手**动态平衡了业务实现与技术改造之间的关系**,使得业务团队必须腾出一部分时间进行技术升级,而不是埋头沉迷于业务迭代。
全链路压测就是众多技术改造类项目的一员。在我目前所在的这家创业公司同样是依托于类似的机制仅仅2个多月的时间便从0到1推动完成了全链路压测的核心改造工作所以你也大可不必把全链路压测想的很难可以尝试用类似的思路去推动它。
组织协调很难,另一个更有难度的问题是,在全链路压测建设完成后,如何将其有效地运营起来,明确每个参与团队要做什么事,做这些事的规范是什么,做的不好的后果是什么等等,这样才能将全链路压测的价值最大化地固化下来。
我的经验是,全链路压测是需要有一个集中式的团队去管理的,这个团队不需要很多人,但是需要被充分授权。可能你会问,光授权也没用啊,别人不听你的怎么办?**这时候就需要通过一些规范去约束和管控了**。
我在做全链路压测运营工作时,建立了两项规范,首先是**全链路压测的常态化执行制度**,每周三晚间低峰期执行全链路压测,核心链路的技术人员和运维人员必须现场值守,其余技术人员可以远程值守。值守人员需要严密关注业务指标,如果出现服务可用性问题或资损问题,及时报告压测团队暂停压测。
如果压测过程中出现服务瓶颈,我们有时候会执行一些降级操作以观察效果,这时候值守人员也应配合操作,如果因为未有效值守导致线上问题,需要承担连带责任。
此外,全链路压测能够暴露出整体系统的容量隐患,但仅仅将问题暴露出来还是不够的,我们需要确认这些问题得到重视和解决,才是真真正正地消除了容量风险,我建立的第二项规范,就是用来驱动全链路压测时所发现问题的及时改进,称之为**容量问题分级规范**。
这项规范根据容量风险的严重程度划定了不同的等级,每个等级对应不同的解决时限要求,越严重的风险,越是需要快速解决,或至少有临时措施。我们会定期统计问题解决的时长达标率,以此作为所有技术团队绩效考评的一个参考标准。
<img src="https://static001.geekbang.org/resource/image/47/20/478fc13efa7546918cedbd549e441520.jpg" alt="">
总结一下,推动全链路压测的落地,不仅仅是一项技术工作,组织协调和运营工作同样重要,否则还是很容易失败的。我比较倡导通过建立机制和流程规范的方式,自上而下去联动和管理多个团队之间的工作,定好的规范要及时跟进并督促执行,尽早暴露风险。
## 总结
关于全链路压测的内容比较多,我们来好好总结一下。全链路压测通过模拟未来流量峰值提前发生,将不确定问题转化为确定性问题,从而达到提前暴露系统整体容量问题的目的。
全链路压测的建设过程,涉及到数据隔离、中间件改造、业务服务改造、压测模型构建和压测流量构造这五项工作,有一定的技术难度和改造量,虽然我在讲解中提供了多种方案,但你在制定技术方案时还是需要平衡好投入产出比。
例如公司大量采用开源技术作为基础设施业务场景也比较简单这时候完全可以不用去动这些基础设施可以直接在业务层进行压测数据的逻辑隔离。构造流量也可以直接使用成熟的开源工具JMeter、Locust等。一句话适合的才是最好的。
全链路压测不是单一的技术问题组织协调和运营工作也需要重点考虑建立一支强有力的全链路压测团队通过流程和机制的制定去管理和规范各个团队的工作是我给到的经验之谈。Program机制、全链路压测常态化执行制度和容量问题分级规范是我给出的三项具体可操作的方法也是我推动或利用的比较成功的例子希望能够给你带来一些启发。
最后,河有两岸,事有两面,全链路压测也不是银弹,无法解决所有问题,将所有容量问题全部交给全链路压测兜底,不再做单链路压测或单服务压测,是错误的实践。全链路压测的实施成本较高,因此其实施频率一般是远远低于业务变更频率的。
全链路压测的擅长点是定期摸底系统整体容量,而常态的容量保障工作应当覆盖每个业务各个接口,这些毛细血管依然需要单链路压测和单服务压测去保障。
<img src="https://static001.geekbang.org/resource/image/b6/a0/b6e09f87aa7ba731471de4e0477e53a0.png" alt="">
## 课后讨论
假设我们通过全链路压测得到结论系统整体能够承载1000TPS每秒下1000单的负载但实际业务达到这个负载时系统却出现了不稳定的情况你觉得在全链路压测工作中可能有哪些地方我们考虑的不够周全从而导致了这一问题欢迎在评论区与我交流你的想法。