众所周知,应用的性能测试,是重要的测试类型之一,对于系统能否稳定运行,起到了关键性验证作用,技术社群的这篇文章《性能测试、分析、优化的方法论》对性能测试的一些方法论知识进行了讲解,科普学习下。

前言

理论来源于实践又服务于实践,性能问题一直是相对复杂的高阶问题,从性能测试到分析再到优化,考验的是工程师的综合IT技能。一个系统整体的性能牵扯到方方面面,硬件配置、网络配置、操作系统、中间件、应用架构、代码质量等等都会影响到系统的整体性能。初入性能领域的工程师可能感觉到无从下手。本文主要介绍相关性能测试、分析、优化的方法论。希望通过方法论的学习,可以帮助工程师在复杂纷乱的环境下明确性能目标,制定合理可行的性能测试计划,有针对性的进行性能分析,发现系统真正的性能瓶颈,并最终能够进行有效的性能优化。

1 相关概念介绍

1.1 软件测试分类

软件测试按照测试阶段、是否运行程序、是否查看源代码以及其他方式,可以用下图所示来描述软件测试的各种分类。

性能测试的一些方法论讲解_性能测试

1.2 性能测试分类

系统的性能是一个很大的概念,覆盖面非常广泛,对一个软件系统而言,包括:执行效率、资源占用、系统稳定性、安全性、兼容性、可靠性、可扩展性等。性能测试是为描述测试对象与性能相关的特征并对其进行评价,而实施和执行的一类测试。它主要通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。通常大家把性能测试、负载测试、压力测试统称为性能测试。

1.基准测试:在给系统施加较低压力时,查看系统的运行状况并记录相关数作为基础。

2.负载测试:是指对系统不断地增加压力或增加一定压力下的持续时间,直到系统的某项或多项性能指标达到安全临界值,例如某种资源已经达到饱和状态等。

3.压力测试:压力测试是评估系统处于或超过预期负载时的运行情况,关注点在于系统在峰值负载或超出最大载荷情况下的处理能力。

4.稳定性测试:在给系统加载一定业务压力的情况下,使系统运行一段时间,以此检测系统是否稳定。

5.并发测试:测试多个用户同时访问同一个应用、同一个模块或者数据记录时是否存在死锁或者其他性能问题。

1.3 不同视角下的软件性能

用户视角的软件性能

从用户的角度来说,软件性能就是用户操作软件的响应时间;用户所体会到的“响应时间”既有客观的成分,也有主观的成分。例如,用户执行了某个操作,该操作返回大量数据,从客观的角度来说,事务的结束应该是系统返回所有的数据响应时间应该是从用户操作开始到所有数据返回完成的整个耗时;但从用户的主观感知来说,如果采用一种优化的数据呈现策略,当少部分数据返回之后就立刻将数据呈现在用户面前,则用户感受到的响应时间就会远远小于实际的事务响应时间。

对于典型的交互系统,2s之内的响应时间通常是被用户所接受的;如果响应时间为5s时,用户的满意程度将会受到一定的影响;当交易响应时间为10s时,那么大多数用户将会不耐烦地关闭交易页面,显然这是非常糟糕的用户体验。

管理员视角的软件性能

管理员视角有时候也就是运维人员的视角。对于运维人员来说,响应时间当然也很重要,运维方关注更多的是系统运行是否平稳(响应时间或者交易吞吐量是否有剧烈波动),CPU、内存、存储等关键资源是否充足。另外,对于银行这样拥有海量用户和较高交易吞吐量的企业来说,系统是否具有较好的可扩展性是很关键的(这决定了是否能够通过资源调配和扩充平稳度过业务高峰),包括,

1.系统的响应时间

2.系统状态的相关信息,如CPU、内存、应用服务器状态、JVM可用内存、数据库的状态等

3.系统的可扩展性,即处理并发的能力

4.系统可能的最大容量和可能的性能瓶颈,通过更换哪些设备或是进行哪些扩展能够提高系统的性能。

5.长时间运行是否足够稳定,是否能够不间断地提供业务服务等。

开发视角的软件性能

开发人员对性能的关注点更多的是系统投产上线后,响应时间是否达到了用户需求说明书中的相关要求。此外,开发人员更加关注编写代码的运行效率、数据库访问是否按照设想的访问路径以及索引设置是否合理等,包括用户和管理员关心的软件性能。

如何通过调整设计和代码实现,或是如何通过调整系统设置等方法提高软件的性能表现。

如何发现并解决软件设计和开发过程中产生的由于多用户访问引发的软件障,也就是通常所说的“性能瓶颈”和系统中存在的在大量用户访问时表现出来的缺陷。

1.4 性能衡量指标

响应时间

请求响应时间指的是客户端发出请求到得到响应的整个过程的时间。这个过程是从客户端发起一个请求开始计时,到客户端接收到从服务器端返回的响应结果为止计时结束。在某些工具中,请求响应时间通常会被称为TTLB,即Time to Last Byte,意思是从发起一个请求开始,到客户端收到最后一个字节的响应所耗费的时间。请求响应时间的单位一般为“秒(s)”或者“毫秒(ms)”。请求响应时间的分解如下图所示:

性能测试的一些方法论讲解_响应时间_02

从图中可以看出,请求响应时间为“网络响应时间”和“应用程序与系统响应时间”之和,具体由七个部分组成,即(N1+N2+N3+N4)+(A1+A2+A3)。

并发用户数

并发用户数也经常被用来作为衡量系统并发处理能力的指标,并发用户数是指系统可以同时承载的正常使用系统功能的用户数量。这个指标也经常被当作衡量系统处理能力的重要指标。实际上,笼统地将并发用户数的大小作为衡量系统并发处理能力的指标并不是十分科学的,因为并发用户又可以细分为在线用户数和严格的并发用户。

在线用户是指在同一时刻处于登录状态的用户,在线用户数仅仅表明有多少用户处于登录状态,并不能说明这些用户正在进行操作,在某些情况下,系统在线用户数可能比较高,但是每秒处理交易数量有可能并不高。

严格的并发用户是指在同一时刻执行统一操作的活跃用户。较少的严格并发用户数可能就会给系统造成较大的压力,实际上绝大多数未经过性能测试和未做调优的应用系统,5~10个严格并发用户就能或多或少地给系统造成性能问题。系统用户数是指系统注册的总用户数。

三者之间的关系:系统用户数≥在线用户数≥严格的并发用户数。

吞吐量

单位时间内处理的客户端请求数量,直接体现软件系统的性能承载能力。通常情况下,吞吐率可以用“请求数/秒”“页面数/秒”来衡量。从网络角度,吞吐量一般以“字节/秒”来衡量。

TPS(Transaction Per Second)

是指每秒钟系统能够处理的交易或者事务的数量,用来衡量系统业务处理能力的重要指标。

对于一些日交易量比较大的系统,通常在测试报告中用每秒完成多少万笔或8/12/24小时完成多少万笔交易来描述系统的业务处理能力,这样可以感觉更直观。

大体来说,对于交互式应用,用户直接的体验是响应时间,通过并发用户数和响应时间可以确定系统的性能规划,但对于非交互式应用,用“吞吐量”来描述我们对系统性能的期望会更加合理。

对于交互式应用来说,吞吐量指标反映的是服务器承受的压力。在容量规划的测试中,吞吐量是一个重点关注的指标,因为它能够说明系统级别的负载能力。另外,在性能调优的过程中,吞吐量指标也有重要的价值。

如在web系统的性能测试过程中,吞吐量以请求数/秒 来体现,吞吐量指标可以在两个方面发挥作用,

用于协助设计性能测试场景,以及衡量性能测试场景是否达到了预期的实际目标。

用于协助分析性能瓶颈,吞吐量的限制是性能瓶颈的一种重要表现形式,因此,有针对性的对吞吐量进行测试,可以尽快定位到性能瓶颈所在位置。比如说,RBI(rapid bottleneck identify)方法就主要通过吞吐量测试发现性能瓶颈。

2 性能测试方法论

2.1 性能测试方法

2.1.1 RBI(rapid bottleneck identify)方法

RBI(rapid bottleneck identify)方法是Empirix公司提出的一种用于快速识别系统性能瓶颈的方法。该方法基于以下一些事实,

1.发现的80%系统的性能瓶颈都由吞吐量制约。

2.并发用户数和吞吐量瓶颈之间存在一定的关联。

3.采用吞吐量测试可以更快速的定位问题。

RBI方法首先访问服务器上的小页面和简单应用,从应用服务器,网络等基础的层面上了解系统吞吐量表现。

其次选择不同的场景,设定不同的并发用户数,使其吞吐量保持基本一致的增长趋势,通过不断增加并发用户数和吞吐量,观察系统的性能表现。

在确定具体的性能瓶颈时,RBI将性能瓶颈的定位按照一种“自下而上”的分析方式进行分析,首先确定是由并发还是由吞吐量引发的性能表现限制,然后从网络,数据库,应用服务器和代码本身4个环节确定系统性能具体的瓶颈。

RBI方法在性能瓶颈的定位过程中能发挥良好的作用,其对性能分析和瓶颈定位有很强的借鉴意义。

2.1.2 性能下降曲线分析法

性能下降曲线实际上描述的是性能随客户数量增加而出现下降趋势的曲线。这里的性能可以是响应时间,也可以是吞吐量。

性能测试的一些方法论讲解_性能测试_03

性能曲线大体分成以下几个部分,

1.性能平坦区

在不进行性能调优的情况下所能期望达到的最佳性能。这个区域可以被用来做性能基线或者benchmark。

2.压力区

应用出现性能轻微下降的地方。典型的,最大的建议用户负载是压力区域的开始。

3.性能拐点

性能开始急剧下降的点。

这几个区域实际上明确标识了系统性能最优秀的区间。系统性能开始变坏的区间,以及性能出现急剧下降的点。

对于性能测试来说,找到这些区间和拐点,就可以找到性能瓶颈产生的地方。

2.2 压力测试工具

针对不同场景,一般有不同层面的性能测试工具。

系统层面,比如Linux环境下,针对不同的系统组件存在不同的系统压测工具。最常见的是系统的sysbench组件包所包含的工具。下图是性能领域领域专家Brendan Gregg的提供linux system bench tools图,供参考。命令的详细用法可以通过man查阅。

性能测试的一些方法论讲解_性能瓶颈_04

应用层面,目前web应用整体一般采用loadrunner或者jmeter进行压力测试。(loadrunner可以通过录制操作自动生成测试脚本。Jmeter可以使用badboy录制操作步骤,生成jmeter运行脚本)。

对于没有web的一些后端应用,特别是基于webservice的微服务,一般采用soapui或者postman进行压力测试(soapui和postman的另一个强大功能是可以根据测试结果自动创建桩代码服务器,这在存在大量关联应用的环境下,尤为有用)。

2.3 性能观测工具

在Linux环境下,存在不同层面的性能观测工具,用于分析不同层面的系统性能。比如常见的nmon、top命令用于系统全局性的观测,sar用于统计性的观测。下面是Brendan Gregg提供的图,供参考。

性能测试的一些方法论讲解_响应时间_05

性能测试的一些方法论讲解_响应时间_06

中间件、数据库层面也有类似工具

如WAS(IBM WebSphere Application Server),就有自带的TPV(Tivoli Performance Viewer)

性能测试的一些方法论讲解_性能瓶颈_07

WAS外部监控工具PTT(WebSphere Application Server Performance Tuning Toolkit)

性能测试的一些方法论讲解_性能瓶颈_08

这些监控工具会提供详细的KPI监控数据,通过分析相关KPI,我们可以确定性能瓶颈或者找到性能瓶颈的可疑点。

2.4 性能分析方法

2.4.1 Ad Hoc核对清单法

当需要检查和调试系统时,技术支持人员通常会花一点时间一步步地过一遍核对清单。一个典型的场景,在产品环境部署新的服务器或应用时,技术支持人员会花半天的时间来检查一遍系统在真实压力下的常见问题。该类核对清单就是Ad Hoc(基于对该系统类型的经验和之前所遇到的问题所罗列的清单)。

举个例子,如下是核对清单中的一项:

运行 iostat-x1检查await列。如果该列在负载下持续超过10(ms),那么说明磁盘太慢或是磁盘过载。

一份核对清单会包含很多这样的检查项目。

这类清单能在最短的时间内提供最大的价值,一般需要频繁更新以保证反映当前状态。这类清单处理的多是修复方法容易记录的问题,例如设置可调参数,而不是针对源 代码或环境做定制的修复。

Ad Hoc核对清单能有效保证所有人都知道如何检查最糟糕的问题,能覆盖到所有显而易见的问题。核对清单必须写得清楚而规范,详细说明如何辨别每一个问题和如何做修复。

举例,

Brendan Gregg提供的60秒针对liunx做基础性能判断的命令列表,如下:

性能测试的一些方法论讲解_性能测试_09

再比如,在一个典型的基于WAS的web应用场景下,下图即可认为是它的Ad Hoc核对清单。

性能测试的一些方法论讲解_性能测试_10

2.4.2 USE方法( utilization、saturation、errors)

该方法的核心是对于所有的资源,查看它的使用率、饱和度和错误。

术语说明,

1.资源:所有服务器物理元器件(CPU、总线…),某些软件资源也能算在内。

2.使用率:在规定的时间间隔内,资源用于服务工作的时间百分比。虽然资源繁忙,但是资源还有能力接受更多的工作,不能接受更多工作的程度被视为饱和度。

3.饱和度:资源不能再服务更多额外工作的程度,通常有等待队列。

4.错误:错误事件的个数。

一旦资源的容量达到100%的使用率,就无法接受更多的工作,资源或者会把工作进行排队(饱和),或者会返回错误。

性能测试的一些方法论讲解_性能瓶颈_11

USE方法会将分析引导到一定数量的关键指标上,这样可以尽快地核实所有的系统资源。实操过程如下:

性能测试的一些方法论讲解_性能瓶颈_12

这个方法辨别出的很可能是系统瓶颈问题。不过,一个系统可能不只面临一个性能问题,因此你可能一开始就能找到问题,但所找到的回题并非你关心的那个。在根据需要返回USE方法遍历其他资源之前,每个发现可以用更多的方法进行调查。

USE方法的第一步是要建一张资源列表,要尽可能完整。下面是一张服务器通常的资源列表例子,

1.CPU:插槽、核、硬件线程(虚拟CPU)

2.内存:DRAM

3.网络接口:以太网端口

4.存储设备:磁盘

5.控制器:存储、网络

6.互联:CPU、内存、IO

一旦你掌握了资源的列表,就可以采集这三类指标:使用率、饱和度,以及错误。

例如,

1.CPU使用率(vmstat 1)

2.CPU饱和度(即运行队列长度 vmstat 1)

3.内存使用率(free -m)

4.内存饱和度(匿名换页或者线程换出再或者OOM)

5.网络接口使用率(sar –n DEV 1)

6.存储使用率(设备繁忙百分比iostat –d –x 1)

7.存储饱和度(等待队列长度iostat –d –x 1)

8.存储设备IO(dmesg smartctl)

数据采集后,根据如下的建议找到瓶颈并进行深入分析:

使用率:100%的使用率通常是瓶颈的信号(检查饱和度并确认其影响)。使用率超过60%可能会是问题,基于以下理由:时间间隔的均值,可能掩盖了100%使用率的短期爆发,另外,一些资源,诸如硬盘(不是CPU),通常在操作期间是不能被中断的,即使做的是优先级较高的工作。随着使用率的上升,排队延时会变得更频繁和明显。

饱和度:任何程度的饱和都是问题(非零)。饱和程度可以用排队长度或者排队所花的时间来度量。

错误:错误都是值得研究的,尤其是随着错误增加性能会变差的那些错误。

2.4.3 延时分析法

延时分析检查完成一项操作所用的时间,然后把时间再分成小的时间段,接着对有着最大延时的时间段做再次的划分,最后定为并量化问题的根本原因。一般情况下,延时分析需要深入到软件栈中的各层去寻找延时问题的原因。

比如说常见的web应用,可以如下图所示,先粗略的划分各组件消耗时间。再深入到各组件内部详细分析延时。

性能测试的一些方法论讲解_响应时间_13

2.5 性能分析遵循的常见原则

2.5.1 2/5/8原则

所谓响应时间的“2-5-8原则”,简单地说:当用户能够在2s以内得到响应时,会感觉系统的响应很快;当用户在2至5s得到响应时,会感觉系统的响应速度还可以;当用户在5至8s得到响应时,会感觉系统的响应速度很慢,但是还可以接受;而当用户在超过8s后仍然无法得到响应时,会感觉系统糟透了,或者认为系统已经失去响应,而选择离开这个Web站点,或者发起第二次请求。

2.5.2 二八原则

二八定律也叫巴莱多定律,是19世纪末20世纪初意大利经济学家巴莱多发明的。该定律的主要内容为:在任何一组东西中,最重要的只占其中一小部分,约20%;其余80%的尽管是多数,却是次要的,因此又称二八法则。用于减少风险、抓住重点进行更多的测试:用户80%的时间在使用软件产品中20%的功能。“重点测试”就是测试这20%的功能,而其他80%的功能属于优先级低的测试范围,占20%的测试资源。

实例:对测试强度估算

基本概念:每个工作日80%的业务在20%的时间内完成。例如每天工作8h,那么每天80%的业务在8×20%=1.6h内完成。

二八原则其他含义

80%的错误是由20%的模块引起的。站在用户角度,并非研发实现的角度出发,正确地选择重要模块作为测试重点将不会偏离方向。

80%的测试成本花在20%的软件模块中。设计用例时需要将时间倾斜花在复杂的20%核心模块上,从而设计更高效的测试用例。

80%的测试时间花在20%的软件模块中。软件测试执行过程中需要将时间倾斜在重要模块的测试用例中,从而使测试更加有效,及时发现bug。

2.5.3 由易到难原则

查找瓶颈时可按以下由易到难的顺序,对于系统运维人员来说,一般习惯于从下往上,从底层系统开始入手分析。比如:

服务器硬件瓶颈→网络瓶颈(对局域网,可以不考虑)→服务器操作系统瓶颈(参数配置)→中间件瓶颈(参数配置、数据库、Web服务器等)→应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)。

而对应用开发人员来说,一般习惯于从熟悉的应用层面开始分析,从上往下进行分析。

2.6 性能调优基本原理

关于如何提高性能,从本质上说只有两个原则,所有的调优方案最终从原理上说都是基于这两个原则。

比如说应用设计中各种缓存的应用,就是提高IO的操作效率。再比如说各类池(连接池、线程池)的大规模使用,也是为了减少资源创建和销毁的动作。

2.6.1 减少操作步骤

性能测试的一些方法论讲解_性能瓶颈_14

2.6.2 提高操作效率

性能测试的一些方法论讲解_性能瓶颈_15

2.7 性能调优遵循的常见原则

性能调优是为了改善系统某些方面的性能而对系统软件或者硬件进行的修改。在性能测试调优过程中需要遵循以下原则,

1.有明确的性能测试目标。

2.在每次调优前,要尽可能对假设做出清晰的、明确的表述。

3.每次调优仅执行一个配置变更。

在每次调优后,使用相同的测试场景,在尽可能一致的后台数据环境进行测试,执行结果要与基线对比分析,确认解决方案是否有效并关注是否带来其他问题。

先整体后局部,层层剥离,即先调系统(操作系统、中间件)、网络,再调数据库,最后调整应用系统。

性能调优的整体过程如下图,

性能测试的一些方法论讲解_性能瓶颈_16

如果您认为这篇文章有些帮助,还请不吝点下文章末尾的"点赞"