gitbook/性能工程高手课/docs/191598.md

176 lines
15 KiB
Markdown
Raw Normal View History

2022-09-03 22:05:03 +08:00
# 25 | 如何在生产环境中进行真实的容量测试?
你好,我是庄振运。
从今天开始,我们进入新的模块:性能工程实践。在这一模块中,我会讲述在实际生产环境中应用性能工程的场景、案例。这些场景和案例都是针对大规模互联网服务,是在解决实际性能问题后总结的经验。
今天我要讲的主题是“在生产环境中进行真实场景的压力测试”。这来源于我对LinkedIn公司生产实践的总结。
LinkedIn为超过5.9亿用户提供服务在性能优化的过程中经常会遇到这类问题一个服务可以承受的最大QPS是多少要满足100K QPS的服务需求我需要多少服务器……
怎么解决这些问题呢,有一个大招就是在生产环境中进行真实的容量测试。
关于这个实践的详细方案和技术细节,我们曾经发表过一篇研究论文([IEEE ICWS](https://ieeexplore.ieee.org/document/8029816)并且很荣幸地获得了IEEE最佳论文奖推荐你去读一读。
今天我就带你从这个场景的源头出发,一步步探索到最后的具体落地方案。
## 为什么需要在生产环境中进行容量测试?
既然我们要解决一个具体的问题,那我们一定要先问个“为什么”。
为什么要在生产环境中进行容量测试呢?要回答这个问题,我们还得再往前追问,为什么说真实的容量测试很重要呢?
我想这个问题不难回答,你应该已经有自己的答案了。
我们都知道,一个在线互联网公司的存活和发展,靠的是它提供的互联网在线服务,自然也就依赖于这些服务的性能和稳定性。要保证每个服务都能够稳定地运行,我们必须为之提供足够的服务容量,比如适当数量的服务器。
那么要如何保证服务容量足够呢?首先就必须做好**服务容量的预测**。
要预测服务容量,我们就需要做容量的性能测试。一般是先确定每台单独的服务器可以支撑多少服务流量;然后用这个单台服务器的数据,来决定这个服务整体需要多少台服务器。这种测试其实就是我们前面讲过的容量测试。
举个具体例子如果测试结果表明一台服务器最多可以支撑100个QPS那么要满足100K QPS的服务需求总共就需要部署一千台服务器。
讲到这里,我想再补充几句。我们讲了这么多服务容量的事儿,那“服务”到底都指的是什么呢?
一般来说公司提供的服务大致上分为两种前端服务和后端服务。前端服务是什么样呢包括各种服务的登陆页面和移动App这些服务会直接影响用户的体验。后端服务呢一般是为前端服务和其他后端服务提供数据和结果。后端服务可以有多种比如键值数据存储服务例如Apache Cassandra和公司内部的各种微服务。
服务容量预测的重要性我们了解了,那测试为什么需要在生产环境中进行呢?
你是不是想到了,在非生产环境中的容量测试,执行起来肯定更简单啊!没错,的确会更简单,但是,在实验环境或者其他非生产环境中做这样的测试,比如采用人工合成的流量负载,会非常不准确。
这是因为实际的生产环境里面,有多个特殊因素会导致和非生产环境中不同的结果。比如:
1. 客户需求会随着时间而变化,例如高峰时段与非高峰时段的流量就很不一样;
2. 用户请求的多样性,例如不同国家的查询类型不同;
3. 负载流量的规模,基础架构设施的变化,例如服务的软件版本更新,微服务互相调用的变化等等。
所以,对一个重要而复杂的互联网在线服务,由于难以在非生产环境中进行准确的容量测试,我们经常需要转向真正的生产环境,使用实时而真实的客户流量负载来测试。
所以,想要在非生产环境中进行准确的容量测试基本上是做不到的。而对一个重要而复杂的互联网在线服务,能够做到准确的容量测试又太重要了。因为准确的容量数据,是保证线上服务的可靠运行和控制公司成本的基础。
那怎么办呢?这时候我们就需要转向真正的生产环境,使用实时而真实的客户流量负载来测试。
## 如何在真实生产环境中进行容量测试?
那在真实生产环境中进行容量测试,要如何做呢?
一般来说我们需要把生产环境的流量进行重定向让这些重定向的流量实时地驱动运行SUT的单个或者几个服务器。根据重定向的流量大小会产生不同级别的流量负载。通过仔细地操作重定向的多少并且把握测试的时间我们可以获得非常准确的运行SUT服务器的容量值。
但是,生产环境中的容量测量也有诸多挑战,你需要特别小心。
第一个挑战是需要**设计一个控制重定向流量的机制**。这个机制要能够根据其他一些参数,来调整重定向的流量多少。
第二个挑战(也是最大的挑战)是这种**重定向生产流量可能会影响真正的客户**。因为我们会把客户请求重定向到某个服务器,并且会不断给服务器加压,直到这个服务器接近超载,那么这个服务器上所有的客户请求的延迟都会受影响,也就是可能会变大,用户性能也就可能会受到损害。
为了尽量减少对客户的影响我们的容量测试需要设计合适的机制来将这种可能的损害降到最低点。系统里面必须有一个模块来不断地监测客户的性能一旦到达临界点就停止继续加压的操作甚至适当减压。这就是所谓的“非侵入性”Non-Intrusive
还有一个挑战是**对于测试时间的控制**。既然重定向生产流量可能影响客户性能,当然是测试的时间越短越好。可是测试时间太短的话,又可能会影响数据的稳定性。
为了应对这些挑战准确地确定服务容量的极限并精确定位容量瓶颈LinkedIn采用了一个解决方案我们将它命名为RedLiner。
宏观来讲Redliner是固定一个生产环境中的SUT这个SUT包括服务器和上面运行的被测服务然后不断地把其他服务器上的流量重定向到这个SUT服务器上面。随着流量的不断增大这个SUT服务器的资源使用也就越来越多所服务的客户请求的性能比如端到端延迟就会越来越差。
直到客户请求的性能差到一个定好的阈值比如端到端延迟是200毫秒流量重定向才会停止。这个时候基本就可以确定SUT服务器不能再处理任何额外的负载。此时获得的容量结果就是SUT服务器的最大容量。
想要实现上述的测试需要好几个模块一起合作。不过在讲RedLiner具体的各个模块之前我们要先梳理一下合理方案的设计原则一共是五条
1. 要使用**实时流量**以确保准确性。
2. 尽量不影响生产流量,这就需要**实时的监测和反馈**模块。
3. 可以**定制重定向**等行为规则;对不同的服务和不同的场景的测试,各种性能指标和阈值都会不同。
4. 能**自动终止测试**,并把**测试环境复位**,尽量减少人工干预。
5. 支持基于日历和事件的**自动触发和调度**。
那这个方案具体是怎么实现的呢?
现在我们来看看解决方案的高层架构,如下图所示,这个方案主要包括四个组件:
* 核心控制器LiveRedliner
* 重定向流量的TrafficRedirector
* 收集性能数据的PerfCollector
* 分析性能数据的PerfAnalyzer
![](https://static001.geekbang.org/resource/image/60/a3/60eb47fd1b2749af61715eaa7dda93a3.png)
我先来一一给你介绍下这四个关键组件。
1.**核心控制组件LiveRedliner**
核心控制组件是整个系统的神经中枢,负责总体调度容量测试的过程。比如何时发起测试,何时终止测试,何时需要增加更大的流量等等。
用户可以自己定义一些特殊的规则来更好地控制整个测试。用户可以自定义性能指标的阈值。这些性能指标可以是用户的端到端延迟包括各种统计指标比如P99。也可以把几个不同的性能指标组合起来实现复杂的逻辑比如“端到端延迟不超过200毫秒并且错误率不超过0.1%等”。
2.**重定向流量组件TrafficRedirector**
重定向流量组件负责对生产流量进行重定向。具体的实现机制,根据被测试的服务类型分为两种:前端服务和后端服务。
用于**前端服务**时Redliner是通过客户请求的属性例如用户ID、语言或帐户创建日期来决定是否对一个客户请求来进行重定向的。这个转换也很简单可以是取模机制。
举个例子来说如果Redliner需要重定向1的流量它可以把用户的一个属性比如userid转换成整数然后执行用100来取模的操作并且和一个固定整数值作比较。
用于**后端服务**时重定向流量可以通过另外一个叫做“资源动态发现和负载均衡”的模块来实现。在LinkedIn我们很多的服务负载均衡机制一般会采用一个服务器列表URI集群以相对应的权重值来决定一个请求发送到哪个服务器。
假设这样一个机制有10个可用的URI集群并且最初所有这些集群都接收等量的流量即每个URI的权重为10。如果Redliner决定将20的流量重定向到特定的URI即SUT那么它可以为SUT的URI分配20的权重。
3.**性能数据收集组件PerfCollector**
容量测试必须采集各种类型的性能指标例如CPU内存和QPS等。这些性能指标的作用就是确定SUT何时达到其容量最大值以及容量值是多少。
PerfCollector组件负责收集各种性能指标包括系统级和服务级的指标。这个组件运行在所有受监视的节点。组件传递的数据量通常很大因为一般要监测较多的性能指标。所以最好采用扩展性好的实时消息传递系统来把这些性能数据及时传到其他组件尤其是下面要介绍的性能分析组件PerfAnalyer。
我们采用的消息传递系统是[Kafka](https://time.geekbang.org/column/intro/100029201)。Kafka也是由LinkedIn设计并开源的扩展性和性能都很好建议你也尝试采用。
4.**性能分析组件PerfAnalyzer**
收集性能指标是第一步下一步就是分析性能并采取相应的措施。具体来说可以根据性能指标的值来确定SUT是否饱和。
根据性能数据和用户定义的规则如果发现当前的SUT仍有空间来承担更多的负载我们可以将更大比例的实时流量重定向到该SUT。否则如果SUT显示饱和迹象那么重定向的流量百分比就应该降低。PerfAnalyzer组件能分析收集的数据并确定是否有特定指标是否违反用户定义的规则。
Redliner作为一个完整的解决方案通过几个模块互相配合来实现真实的线上容量测试。通过动态地调整线上的流量直到让被测系统临近超载状态从而获得准确的单位服务容量。
现在我们再来换个角度看一下RedLiner的具体操作流程。流程图如下所示。
![](https://static001.geekbang.org/resource/image/f1/51/f1da037ebb3a7e3a98fcdf31b7a37851.png)
首先是**跟据以前的测试历史数据决定一个初始重定向数量也就决定了SUT的初始负载**。理论上讲,每个测试都可以从0开始;但是如果起点流量太低,整个测试需要花很长时间,所以最好能利用历史数据,从一个比较高的起点开始。
在使用历史数据的基础上,我们还需要**决定总体测试时间**。决定了时间后每次调整重定向流量的百分比也就确定了。这个调整的数值大小也就是所谓的“步距”如同人迈步走路每一步都有大小。对每个百分比我们一般固定测试3分钟让数据稳定下来然后调用PerfAnalyzer分析并决定下一步。
举个例子假如我们决定总体测试60分钟并且是从0%开始。因为每一个百分点需要测试3分钟那么我们就会决定调整的“步距”大小是5%因为最大就是100%。如果PerfAnalyzer决定需要继续增加或者减少重定向百分比那么就按照前面决定的步距进行相应的调整。
## 一起来看两个生产环境的数据
刚才讲了一大堆如何实现这个解决方案的内容现在我们来看看两个生产环境中的实际数据来直观地感受一下这个系统的特点。下图显示了典型Redliner运行的特征。
![](https://static001.geekbang.org/resource/image/b5/0f/b532a67de294378cd7ee9bf4ede3b00f.png)
这是一次完整的容量测试,持续了一个小时。
第一幅图是QPS也就是系统吞吐量。蓝色线表示SUT有望实现的目的QPS。红色线是SUT实现的实际QPS。我们可以看到实际的QPS值持续变化这个变化表明了Redliner的控制和探测过程就是一直在动态增加和减少重定向流量百分比。
![](https://static001.geekbang.org/resource/image/53/45/53a13bbb560a6c03ac89507e5e42c845.png)
第二幅图,标识出了所测量的客户查询等待时间的中值。
比较这两幅图你可以看到开始测试的阶段RedLiner不断提高重定向百分比实际的流量持续增加同时客户感受的查询等待时间也慢慢加大。
等到SUT不堪重负时查询等待时间也就太大了超出了客户能接受的阈值40毫秒。所以RedLiner决定逐步降低重定向百分比最后重置到初始状态。
## 总结
我们这一讲介绍了一个在生产环境中,进行真实场景压力和容量测试的方案,这里面的关键点,是**逐步而智能地把一部分流量重定向到被测试的系统上面**。
这个案例是我们在领英的生产实践,但我觉得在你的公司里实现这么一个类似的系统一点也不难。希望这些分享能帮助你设计和实现。
![](https://static001.geekbang.org/resource/image/2d/94/2d5aac1c39d5c8ce8467d5752f080e94.png)
唐代诗人白居易的《长相思》最后的几句是:“愿作远方兽,步步比肩行。愿作深山木,枝枝连理生。”说的是主人公愿意与心爱的人相守到老,哪怕是做山林中的野兽和树木,一起步步连心,亦步亦趋,比肩而行,并肩而居。
我们用实际的生产负载做容量测试时,要小心控制重定向的流量“步距”大小,尽量“小步勤挪”,并且实时地观测,才不会影响客户的体验,并且得到比较准确的结果。
## 思考题
你们公司有没有类似的解决方案,来准确地测量一个服务需要的容量呢?如果有,和我讲的具体方案有何异同?不同的地方是基于什么考虑呢?
如果没有,你可以考虑实现一个,我相信一定会让老板对你另眼相看的。
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。