性能测试概念

性能测试针对系统的性能指标,建立性能测试模型,制定性能测试方案,制定监控策略,在场景条件之下执行性能场景,分析判断性能瓶颈并调优,最终得出性能结果来评估系统的性能指标是否满足既定值。

  • 性能测试需要有指标, 时间指标, 容量指标, 以及资源利用率指标
  • 性能测试需要有模型, 业务模型, 以在压测时控制并发比例贴近真实场景
  • 性能测试要有方案, 方案规定的内容有几个关键点, 分别是测试环境, 测试数据, 测试模型, 性能指标, 压力策略, 准入准出和进度风险, 用项目管理工具(如Project, OmniPlan)单独画测试计划
  • 性能测试要有监控, 监控要有分层, 分段的能力, 要有全局监控, 定向监控的能力
  • 性能测试要有预定的条件, 条件包括软硬件环境, 测试数据, 测试执行策略, 压力补偿等内容
  • 性能测试要有场景, 在既定的环境(包括动态扩展等策略)、既定的数据(包括场景执行中的数据变化)、既定的执行策略、既定的监控之下,执行性能脚本,同时观察系统各层级的性能状态参数变化,并实时判断分析场景是否符合预期。
    • 基准性能场景:这里要做的是单交易的容量,为混合容量做准备
    • 容量性能场景:这一环节必然是最核心的性能执行部分。根据业务复杂度的不同,这部分的场景会设计出很多个
    • 稳定性性能场景:在稳定性测试中,显然最核心的元素是时间(业务模型已经在容量场景中确定了),而时间的设置应该来自于运维周期,而不是来自于老板、产品和架构等这些人的心理安全感。
    • 异常性能场景:要做异常性能场景,前提就是要有压力。在压力流量之下,模拟异常。
  • 性能测试要有分析调优
  • 性能测试要有结果报告, 应该在报告中写上调优前后的 TPS、响应时间以及资源对比图

总结
image.png

TPS与响应时间的关系

image.png

在这个图中,定义了三条曲线、三个区域、两个点以及三个状态描述。

  • 三条曲线:吞吐量的曲线(紫色)、利用率(绿色)、响应时间曲线(深蓝色)。
  • 三个区域:轻负载区(Light Load)、重负载区(Heavy Load)、塌陷区(Buckle Zone)。
  • 两个点:最优并发用户数(The Optimum Number of Concurrent Users)、最大并发用户数(The Maximum Number of Concurrent Users)。
  • 三个状态描述:资源饱和(Resource Saturated)、吞吐下降(Throughput Falling)、用户受影响(End Users Effected)。

这张图只能作为示意图, 与实际项目存在偏差:

  • 很多时候, 重负载区的资源饱和, 和TPS达到最大值之间都不是在同样的并发用户数之下的, 比如当CPU资源使用率达到100%之后, 随着压力的增加, 队列慢慢变长, 响应时间增加, 但是由于用户数增加的幅度大于响应时间增加的幅度之前, TPS依然会增加, 也就是说资源使用率达到饱和之后还有一段时间TPS才会达到上限
  • 大部分情况下, 响应时间的曲线都不会像图中那样陡峭, 也不一定是在塌陷区突然上升, 更可能的是在重负载区突然上升
  • 吞吐量曲线不一定会出现下降的情况, 在有些控制较好的系统中会维持水平
  • 最优并发数通常只是一种感觉, 没有绝对的数据证明, 在生产运维中, 一般会谨慎的定的更靠前一些
  • 最大并发数在更靠前的位置(ps: 啥情况, 图中没有并发数的点呀~~)
  • 没有考虑锁或线程等配置不合理的场景, 这些场景会导致TPS上不去, 资源用不上, 图中默认的前提是, 只要线程用的上, 资源就会往上涨

在实际的项目实施:

  1. 更关心服务端能处理的请求数TPS, 而不是压力工具中的线程数
  2. 性能测试与分析目标在于控制容量的水位, 控制系统在饱和点之前

简化后的图形
image.png
蓝线表示TPS, 黄线表示响应时间

  1. TPS不断增加, 响应时间一开始较低, 在A点之前
  2. 响应时间增加到业务可以承受的时间点B, 此时TPS依然有增长的空间
  3. 响应时间增加到C点, 达到最大TPS, 再加压力, 响应时间接着增加, 但TPS会有下降(在一些队列, 熔断限流等控制较好的系统, 并不会下降)
  4. 最后响应时间过长, 达到超时

一般在生产中, 期望将系统TPS控制在B点之前

以场景替换测试概念

image.png

“单交易容量测试”是对单独接口进行压测是吧?比如针对每一个接口都测了100、200、300并发。那么这个测试结果和“混合容量性能场景”测完的结果应该怎么对比分析呢? 作者回复: 不用对比分析。 做单交易容量测试是为了混合容量做基准数据的。举例来说。 业务1单交易容量能达到300TPS,且响应时间也非常好。而在混合中,可能业务1只需要100TPS,那就说明业务1不会成为混合容量的瓶颈点。 如果业务1单交易容量的时候只能达到50,而在混合场景中需要它能跑到100,怎么办?这就只能在单交易的时候做优化了。 所以单交易容量测试是为了确定是不是应该在单交易容量阶段做性能优化。 题外话:要注意的是混合容量中有相互的逻辑关系,这个必须到混合容量的时候才会出现。

性能场景为什么要连续?而不是断开? 递增线程数,记录每次的性能指标,对比分析,画曲线,来观察指标变化的趋势,找出性能瓶颈,或者服务器最大处理能力 递增加压的过程是为了让一个系统的性能衰减过程可以清晰判断出来

TPS, QPS, RT, 吞吐量

业务指标与技术指标

  • 通常从两个层面定义性能场景的需求指标:业务指标和技术指标
  • 技术问答”一个系统在多少响应时间下能支持多少TPS”, 业务问答”1000万人在线会不会有问题?”
  • 所有的技术指标都是在有业务场景的前提下制定的,而技术指标和业务指标之间也要有详细的换算过程

image.png

性能指标表示法

常用的性能指标表示法
image.png

  • TPS(Transactions Per Second)用来描述每秒事务数, TPS 在不同的行业、不同的业务中定义的粒度都是不同的, 如果是接口层性能测试,T 可以直接定义为接口级;如果业务级性能测试,T 可以直接定义为每个业务步骤和完整的业务流。
  • 建议直接用TPS就行了
  • 响应时间(Response Time), 响应时间的拆分定位是性能瓶颈定位分析中非常重要的一节

压力工具中线程数和用户数与TPS

  • 并发线程数在没有模拟真实用户操作的情况下,和真实的用户操作差别非常远
  • 通常,我们会对在线的用户做并发度的分析,在很多业务中,并发度都会低于 5%,甚至低于 1%。拿 5% 来计算,就是 10000 用户 x5%=500(用户级 TPS),注意哦,这里是 TPS,而不是并发线程数。如果这时响应时间是 100ms,那显然并发线程数是 500TPS/(1000ms/100ms)=50(并发线程)。

image.png

28模型 有些文章中写性能测试要按 28 原则来计算并发用户数。大概的意思就是,如果一天有 1000 万的用户在使用,系统如果开 10 个小时的话,在计算并发用户数的时候,就用 2 小时来计算,即 1000 万用户在 2 小时内完成业务。

这个逻辑在一个特定的业务系统中是没有任何价值的。因为每个系统的并发度都由业务来确定,而不是靠这样的所谓的定律来支配着业务。

业务模型应该如何得到呢?

  1. 根据生产环境的统计信息做业务比例的统计,然后设定到压力工具中。有很多不能在线上直接做压力测试的系统,都通过这种方式获取业务模型。
  2. 直接在生产环境中做流量复制的方式或压力工具直接对生产环境发起压力的方式做压力测试。这种方式被很多人称为全链路压测。

响应时间如何设计比较合理呢?

  1. 同行业的对比数据。
  2. 找到使用系统的样本用户(越多越好),对他们做统计,将结果拿出来,就是最有效的响应时间的制定标准。

如何做系统容量的预估呢?

  1. 根据现有的数据,做统计分析、做排队论模型,进而推导以后的系统容量
  2. 系统的容量是演进来的,而不是光凭预估就可以得出准确数值的。

JMeter和LoadRunner

常用工具
image.png
对比
image.png

总结: 首选JMeter…

并发用户数的计算

并发

  • 绝对并发指的是同一时刻的并发数;
  • 相对并发指的是一个时间段内发生的事情。

建议用 TPS 来承载“并发”这个概念。并发数是 16TPS,就是 1 秒内整个系统处理了 16 个事务。

并发度

同一时间内同时对后端服务做操作的请求数 算并发用户数

如上图所示,总共有 32 个用户进入了系统,但是绿色的用户并没有任何动作,那么显然,在线用户数是 32 个,并发用户数是 16 个,这时的并发度就是 50%。
image.png

在线最大用户数

缓存的内存大小做计算估计最大在线用户数

为了能 hold 住更多的用户,我们通常都会把一些数据放到 Redis 这样的缓存服务器中, 再加上在超时路上的用户数, 即可估算在线最大用户数
假设一个用户进入系统之后,需要用 10k 内存来维护一个用户的信息,那么 10G 的内存就能 hold 住 1,048,576 个用户的数据,这就是最大在线用户数了。在实际的项目中,我们还会将超时放在一起来考虑。
image.png

补充:

通常说的“并发”这个词,依赖 TPS 来承载的时候,指的都是 Server 端的处理能力,并不是压力工具上的并发线程数。在上面的例子中,我们说的并发就是指服务器上 100TPS 的处理能力,而不是指 5 个压力机的并发线程数

TPS计算

在压力机上启动 10 个线程。结果如下

  1. summary + 11742 in 00:00:30 = 391.3/s Avg: 25 Min: 0 Max: 335 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
  2. summary = 55761 in 00:02:24 = 386.6/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
  3. summary + 11924 in 00:00:30 = 397.5/s Avg: 25 Min: 0 Max: 80 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
  4. summary = 67685 in 00:02:54 = 388.5/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
  5. summary + 11884 in 00:00:30 = 396.2/s Avg: 25 Min: 0 Max: 240 Err: 0 (0.00%) Active: 10 Started: 10 Finished: 0
  6. summary = 79569 in 00:03:24 = 389.6/s Avg: 25 Min: 0 Max: 346 Err: 0 (0.00%)
  1. 可以看到平均响应时间为25ms
  2. 1s可以接收1000/25=40个请求, 由于是10个线程, 因此TPS=40*10=400

对于压力工具来说,只要不报错,我们就关心 TPS 和响应时间就可以了,因为 TPS 反应出来的是和服务器对应的处理能力,至少压力线程数是多少,并不关键。

总结:
TPS=(1000ms/响应时间(单位ms))∗压力机线程数

性能分析思路

性能测试分析的能力阶梯视图
image.png

  1. 工具操作:包括压力工具、监控工具、剖析工具、调试工具。
  2. 数值理解:包括上面工具中所有输出的数据。
  3. 趋势分析、相关性分析、证据链分析:就是理解了工具产生的数值之后,还要把它们的逻辑关系想明白。这才是性能测试分析中最重要的一环。
  4. 最后才是调优:有了第 3 步之后,调优的方案策略就有很多种了,具体选择取决于调优成本和产生的效果。

1. 瓶颈的精准判断

TPS曲线

  • 大部分系统没有明确的”拐点”
  • TPS 的衰减过程大概会如下所示

image.png

  • 随着用户数的增加,响应时间也在缓慢增加。
  • TPS 前期一直都有增加,但是增加的幅度在变缓,直到变平。
  • 对于TPS曲线来说, 可以明确的是:
    • 有没有瓶颈(准确来说所有的系统都有性能瓶颈)
    • 瓶颈和压力有没有关系, TPS 随着压力的变化而变化,那就是有关系。不管压力增不增加,TPS 都会出现曲线趋势问题,那就是无关

示例一, TPS以及RT图如下
image.png
image.png

  • TPS曲线从第一个阶梯到第二个阶梯, 以及第二个阶梯到第三个阶梯, 增加的越来越少, 说明TPS的增长赶不上压力的增长, 系统处理不过来了, 表现为响应时间的增加, 因此系统在第二个压力阶梯已经有瓶颈了, 越往后越明显
  • 瓶颈与压力有关

示例二
image.png

  • 有瓶颈
  • 瓶颈与压力有关
  • 压力也是阶梯的, 但是没有明确的拐点’’

示例三
image.png

  • 有瓶颈
  • 瓶颈与压力无关

响应时间曲线

  • TPS 就可以告诉我们系统有没有瓶颈了,而响应时间是用来判断业务有多快的。

示例, 响应时间曲线与线程图与TPS图
image.png
image.png
image.png

  • 到第 40 个线程时,TPS 基本上达到上限,为 2500 左右。响应时间随着线程数的增加而增加了,系统的瓶颈显而易见地出现了

2. 线程递增的策略

  • 对一个系统来说,如果仅在改变压力策略(其他的条件比如环境、数据、软硬件配置等都不变)的情况下,系统的最大 TPS 上限是固定的
  • 即使线程数增加得再多,对已经达到 TPS 上限的系统来说,除了会增加响应时间之外,并无其他作用。

对于场景中线程(有些工具中叫虚拟用户)递增的策略,我们要做到以下几点:

  1. 场景中的线程递增一定是连续的,并且在递增的过程中也是有梯度的
  2. 场景中的线程递增一定要和 TPS 的递增有比例关系,而不是突然达到最上限
  3. 上面两点针对的是常规的性能场景。对于秒杀类的场景,我们前期一定是做好了系统预热的工作的,在预热之后,线程突增产生的压力,也是在可处理范围的。这时,我们可以设计线程突增的场景来看系统瞬间的处理能力。如果不能模拟出秒杀的陡增,就是不合理的场景

性能场景递增的经验值
image.png

3. 性能衰减的过程

image.png

  • 通过红线的大致比对可以知道,当每线程每秒的请求数降到 55 左右的时候,TPS 就达到上限了,大概在 5000 左右,再接着往上增加线程已经没有用了,响应时间开始往上增加了
  • 这就是性能衰减的过程(题外话,在上图中,其实还有一个问题,就是在红线前面,性能在上升的过程中有几次抖动,这个抖动到后面变大了,也变频繁了,如果这是必然出现的抖动,那也是配置问题,希望你注意到这一点)。

只要每线程每秒的 TPS 开始变少,就意味着性能瓶颈已经出现了。但是瓶颈出现之后,并不是说服务器的处理能力(这里我们用 TPS 来描述)会下降,应该说 TPS 仍然会上升,在性能不断衰减的过程中,TPS 就会达到上限。这也是前面我说的,性能瓶颈其实在最大 TPS 之前早就已经出现了。

那么我们是不是应该在性能衰减到最大 TPS 时就停止场景呢?这个不一定的哦。 因为停不停场景,取决于我们的场景目标,如果我们只是为了得到最大 TPS,那确实可以停止场景了。但是,如果我们要扩大化性能瓶颈,也就是说为了让瓶颈更为明显,就完全不需要停止场景,只要不报错,就接着往上压,一直压到我们要说的下一个话题——响应时间变长,需要拆分。

4. 响应时间的拆分

其实不管我们用什么样的工具来监控,最终我们想得到的无非是每个环节消耗了多长时间。用日志也好,用链路监控工具也好,甚至抓包都可以。

5. 构建分析决策树

image.png

操作系统分析决策树
image.png

6. 场景的比对

当你觉得系统中哪个环节不行的时候, 又没能力分析它,你可以直接做该环节的增加。
当我们不知道系统中哪个环节存在性能瓶颈时,对架构并不复杂的系统来说,可以使用这样的手段,来做替换法,以快速定位问题。

总结 本节内容主要讲了性能分析思路。从6个方面来分析: 首先,要准确的判断瓶颈点。通过什么来判断呢?TPS曲线。TPS曲线能够告诉我们系统是否有瓶颈,以及瓶颈是否与压力有关。为什么不需要响应时间曲线来判断呢?因为响应时间主要是用来判断业务快慢的。

其次,我们要确定我们设置的性能场景是正确的,线程是逐渐递增的,而不应该一上来就上几百个线程。原因:1、直接上几百个线程不符合一般情况下的真实场景。2、即使是秒杀场景也有个“数据预热”的过程(我的理解,数据预热跟线程递增应该差不多,有一个由小到大逐渐增加的过程)3、对于TPS已经到达上限的系统来说,除了响应时间的增加,没有其他作用。

再次,我们要拥有能判断性能衰减的能力。如何判断?分段计算每线程每秒的TPS,如果这个数值开始变少,那么性能瓶颈就出现了。此时再随着线程的增加,性能逐渐衰减,TPS逐渐达到上限。

然后,我们知道性能开始衰减了,那么是什么原因导致的衰减?此时就需要对响应时间进行拆分,拆分的前提需要熟悉系统的架构,拆分的目的是要知道每个环节消耗的时间,拆分的方法可以通过日志,可以通过监控工具,也可以通过抓包.

再然后,最重要的地方到了,我们要逐步构建自己的分析决策树。随着性能分析经验的累加,我们需要整理并总结每次遇到的性能问题以及相对应的解决方法,同时我们还要不断扩充自己的知识库:系统架构、操作系统、数据库、缓存、路由等等,并将这些知识与经验结合起来。重新梳理,由大到小,由宏观到细节,去画出自己的分析决策树。

最后一点感觉是对第一条的补充,而且应该也是对小白(比如我)的一个提点,当我们刚开始进行性能分析,没有思路的时候,那就可以通过这种替换法来帮助我们快速定位问题。当然,这种方法比较适合简单的系统,如果系统很复杂,这样替换不一定方便了。

补充

为什么线程递增过程不能断?

这里涉及开篇提到的性能分析能力 ——「趋势分析」。 就像之前提到的一样,分析性能数据趋势需要对一个时间序列数据的分析,一般采用「线性回归分析」算法。 回归分析研究的是多个变量之间的关系。它是一种预测性的建模技术,它研究的是因变量(目标)和自变量(预测器)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。 假设有 N 个样本点,这里我们可以简单理解线性回归算法就是求一条直线 Y=f(X),使得各点到这个曲线的距离的绝对值之和最小。 在这种技术中,因变量(TPS)是连续的,自变量(线程数)可以是连续的也可以是离散的,回归线的性质是线性的。

但在性能测试中,由于系统本身的最大 TPS 上限是固定的,即服务端的处理能力(容量)是固定的,如果自变量(线程数)压力过大,那么系统平均处理时间(响应时间)会被拉长。不过这个时候其实瓶颈早就出现了。 所以在场景压测中的自变量(线程数)递增一定需要是连续的,并且在递增的过程中要有梯度的,且场景中的线程递增一定要和因变量(TPS) 的递增有比例关系,且不是突然达到最上限,这样才能准确找出系统的瓶颈点。