1. 什么是软件性能?
在不同角色的眼中,软件性能是不同的。
1.1 用户眼中的软件性能
从用户角度来说,软件性能就是软件对用户操作的响应时间。从单击一个按键、发出一条指令或是在web页面上单击一个链接开始,到应用系统把本次操作的结果以用户能察觉的方式展示出来的过程所消耗的时间就是用户对软件性能的直观印象。必须明确,用户所体会到的响应时间有客观成分,也有主观成分。例如,用户执行了某个操作,该操作返回大量的数据。客观上,响应时间应该是从用户进行操作直至所有数据都返回结束所花费的所有时间。但从用户感知的角度来说,如果采用一种优化的数据呈现策略,当少部分数据返回之后就立刻将数据呈现在用户面前,用户感觉到的响应时间就会远小于实际的事务响应时间。
1.2 管理员视角的软件性能
管理员关心的问题 | 软件性能描述 |
服务器的资源使状况合理么? | 资源利用率 |
应用服务器和数据库的资源使用状况合理么? | 资源利用率 |
系统是否能够实现扩展 | 系统可扩展性 |
系统最多能支持多少用户的访问?系统最大的业务处理量是多少? | 系统容量 |
系统性能可能的瓶颈在哪里? | 系统可扩展性 |
更换哪些设备能够提高系统性能 | 系统可扩展性 |
系统能否支持7*24小时业务访问 | 系统稳定性 |
1.3 开发人员关注的软件性能
开发人员关心的问题 | 问题所属层次 |
架构设计是否合理 | 系统架构 |
数据库设计是否存在问题 | 数据库设计 |
代码是否存在性能方面的问题 | 代码 |
系统中是否有不合理的内存使用方式 | 代码 |
系统中是否存在不合理的线程同步方式 | 设计与代码 |
系统中是否存在不合理的资源竞争 | 设计与代码 |
1.4 web前端性能
前端性能,尤其是web前端性能,已经成为目前web应用性能主要被关注的部分之一。各种web前端技术使得服务器端的响应时间在用户感受到的响应时间中所占的比例越来越小。web应用的前端响应时间指浏览器的页面加载时间。一般而言,浏览器的页面加载时间包括对html的解析、对页面上的图片及css等文件的获取和加载、客户端脚本(javascript)的执行时间以及对页面进行展现所花费的时间,这部分性能体现就被称为前端性能。虽然浏览器端的脚本也需要从服务器获得数据(性能依赖服务器端),但这一过程所消耗的时间不构成前端响应时间的主要成分。所以web前端性能更关注的是浏览器的页面元素加载、客户端代码执行以及页面展现相关。如何提高浏览器下载和执行资源的并发性,如何让浏览器尽快开始渲染页面,如何让浏览器尽可能充分地利用缓存等问题是前端性能关注的主要问题。
2 软件性能的几个主要术语
2.1 响应时间
如上所述,响应时间是软件性能中最重要的指标之一。响应时间可表示为:响应时间=前端响应时间+后端服务器响应时间=网络传输时间+应用延迟时间。不用应用的用户对响应时间的要求是不一样的。如对一个电子商务网站,在美国和欧洲,一个普遍的标准为2/5/10。即2秒内响应为“非常好”,5秒内响应为“可接受”,10秒是客户接受的响应上限。
2.2 并发用户数
可从业务角度和服务端两个角度来理解并发用户数。从业务角度来看,越多的用户同时使用系统,系统承受的压力越大,也越容易出现由于同时访问导致的资源争用等问题。而从服务端的角度来看,某一时刻越多同一服务请求,服务器端承受的压力越大,可考虑通过并发测试发现系统中存在的并发引起的资源争用问题。举例来说,若采用前一种“并发”概念,同样是2000人规模的并发用户数,如果场景不同(如所有用户平均每2/5/10秒单击一次鼠标,发起一个业务),服务器承受的压力是完全不同的。而若采用后一种“并发”概念,如果每种场景具有相同的最大并发用户数,则说明这两种情况下服务器的最大压力是相同的。
服务器端实际承受的压力不只取决于业务并发用户数,还取决于用户的业务场景。比如,某系统有500人在线,有80%的用户在阅读,只20%的用户在不停地从一个页面跳转到另一个页面。可见,只有这20%的用户能给服务器端造成压力。可以通过对服务器日志的分析得到系统服务端承受的最大并发访问数量。除此之外,还可用一些公式来对并发用户数进行估算。为了更好的了解系统的性能,测试人员应根据典型业务场景(也就是用户最常使用、最关注的业务操作)来选择一个合适的并发用户数。
2.3 吞吐量
吞吐量直接体现软件系统的性能承载能力,是指单位时间内系统处理的客户请求的数量,可用请求数/秒或页面数/秒来衡量(主要用于测试web系统的性能),也可用访问人数/天或处理的业务数/小时(业务角度)等单位来衡量,还可以用字节数/天(网络角度)来考察网络流量。
对于交互式应用,通过“并发用户数”和“响应时间”可以确定系统的性能规划;但对于非交互式应用,用“吞吐量”来描述用户充分体现期望可能更加合理。在容量规划的测试中,吞吐量是一个重点关注的指标,因为它能够说明系统级别的负载能力。吞吐量可用于协助设计性能测试场景,衡量性能测试场景是否达到了预期的设计目标。在性能调优的过程中,吞吐量指标也有重要的价值,可用于协助分析性能瓶颈。吞吐量的限制是性能瓶颈的一种重要表现形式,因此,有针对性地对吞吐量设计测试,有助于尽快定位到性能瓶颈所在位置。
以不同方式表达的吞吐量可以说明不同层次的总量。如,以字节数/秒方式表示的吞吐量主要受网络基础设施、服务器架构、应用服务器制约;以单击数/秒方式表示的吞吐量主要受应用服务器和应用代码的制约。
在没有遇到性能瓶颈时,吞吐量可采用如下公式计算:F = N(VU) * R / T,其中,N(VU)代表并发用户数量(virtual user),R代表每个VU发出的请求(单击)数量;T表示性能测试所用的时间。但如果遇到性能瓶颈,则该公式不成立。当N(VU)增大到一定程度时,就会遇到性能瓶颈。虽然可对系统施加相同的吞吐量压力进行测试,但系统的性能表现也与用户使用场景有关。例如,测试A采用100个并发,每个并发每1秒发送1个请求,而测试B采用1000个并发,每个并发每10秒发送1个请求。虽然两个测试中,吞吐量都为100(100*1/1=1000*1/10),但在测试A中应用在50pages/sec出现性能瓶颈,而测试B则在25pages/sec出现性能瓶颈。
2.4 性能计数器
性能计数器是描述服务器或操作系统性能的一些数据指标,是性能测试分析的主要参考值。例如,内存数、进程时间等都是常用的性能计数器。计数器在性能测试中发挥着监控和分析的关键作用,尤其是在分析系统的可扩展性、进行性能瓶颈的定位时,对计数器取值的分析非常关键。例如,某系统在承受10000个用户的并发访问时,web服务器的cpu占用率为90%,平均的内存占用率为20%,则可清楚地知道,cpu很有可能是系统的一个性能瓶颈。
性能计数器类似于西医看病时进行各种身体检查得到的数据,性能测试工程师可通过这些数据找到系统的性能瓶颈。可通过如下方法来分析系统的性能:内存分析法、处理器分析法、磁盘I/O分析法、进程分析法、网络分析法等。另外,不同的应用服务器(如IIS应用服务器、J2EE应用服务器、数据库服务器)关注的性能计数器也各有所偏重。
2.5 思考时间(休眠时间)
从业务的角度来说,用户在进行操作时,每个请求之间会有一段时间。这个时间就被称为思考时间。自动化测试实现时,要真实地模拟用户操作,必须在测试脚本中让各个操作之间等待一段时间。设置多长的思考时间最为合理是许多性能测试工程师关心的问题。吞吐量计算公式中提到的R可以表示为: R = T / T(s),其中T(s)为思考时间。可通过以下步骤来计算思考时间:
- 首先计算出系统的并发用户数N(VU)
- 统计出统计的吞吐量F
- 统计出平均每个用户发出的请求数量R
- 根据T(s)=T / R来计算出T(s)
如果测试的目的是为了验证应用系统具有预期的能力,就应该尽量模板用户在使用业务时的真实思考时间;如果目的是进行更一般的研究,例如了解系统在压力下的性能水平或系统承受压力的能力,则可采用0思考时间。
2. 性能测试的方法及应用领域
2.1 性能测试方法
性能测试包括如下方法:验收性能测试(也即狭义的性能测试)、负载测试、压力测试、配置测试、并发测试、可靠性测试、失败恢复测试。性能测试、负载测试和压力测试三者的区别经常被问到,具体请见:
- 验收性能测试:通过模拟生产运行的业务压力和使用场景组合,测试系统的性能是否满足生产性能要求。是一种最常见的测试方法,通俗地说,这种测试方法就是要在特定的运行条件下验证系统的能力状况。
- 负载测试:在一定的软件、硬件及网络环境下,运行一种或多种业务,在不同虚拟用户数量的情况下,测试服务器的性能指标是否在用户的要求范围内,以些确定系统所能承载的最大用户数、最大有效用户数以及不同用户数下的系统响应时间及服务器的资源利用率。大多数的性能测试都是负载测试。
- 压力测试:在一定的软件、硬件及网络环境下,模拟大量的虚拟用户向服务器产生负载,使服务器的资源处于极限状态下并长时间连续运行,以测试服务器在高负载情况下是否能够稳定工作。与负载测试获得贬值性能数据不同,压力测试强调在极端情况下系统的稳定性和可恢复性,这个时候处理能力已经不重要了。
- 容量测试:指在一定的软件、硬件及网络环境下,在数据库中构造不同数量级别的数据记录,运行一种或多种业务在一定虚拟用户数量的情况下,获取不同数量级别的服务器性能指标,以确定数据库的最佳容量和最大容量。容量测试不仅可以对数据库进行,还可以对硬件处理能力、各种服务器的连接能力等进行,以此来测试系统在不同容量级别下是否能达到指定的性能。
- 配置测试:通过对被测系统软硬件环境的调整,了解各种不同环境对系统性能影响的程度,从而找到系统各项资源的最优分配原则。此配置测试方法不同于与功能测试并列的那个“配置测试”方法。
- 并发测试:通过模拟用户的并发访问,测试多用户并发访问同一个应用、同一个模块或者数据记录时是否存在死锁或者其他性能问题。
- 可靠性测试:通过给系统加载一定的业务压力(例如资源在70%-90%的使用率),让应用持续运行一段时间,测试系统在这种条件下能否稳定运行。一般用平均无故障时间或失效率来衡量。
- 失效恢复测试:针对有冗余备份和负载均衡的系统设计的。这种测试以用来检验如果系统局部发生故障,用户是否能够继续使用系统,以及如果这种情况发生,用户将受到多大程度的影响。不是所有的系统者,尤其是并没有明确给出系统持续运行指标的系统。
2.2 性能测试应用领域
性能测试主要应用在如下领域:能力验证、规划能力、性能调优、缺陷发现象和性能基准比较。
- 能力验证:主要用于验证系统的性能是否达到要求
- 规划能力:比较关心应该如何使系统具有我们要求的性能能力,或是在某种可能发生的条件下,系统具有如何的性能能力。规划能力应用领域内的问题常常会被描述为:“某系统能否支持段时间内的用户增长”或者“应该如何调整系统配置,使系统能够满足增长的用户数的需要”。它是一种探索性的测试,可被用于了解系统的性能以及获利扩展性能的方法。
- 性能调优:如字面意义,性能调优主要在于调系统的硬件环境、系统设置和应用级别的调整来使系统的性能更好。
- 缺陷发现:通过性能测试的手段来发现象系统中存在的缺陷。
- 性能基准比较:常应用在敏捷开发过程上。敏捷软件开发具有小步快走、快速的需求变化等特征,在一个迭代中,由于迭代的时间周期很短,且产品本身的需求变化频繁,因此很难象传统软件开发方法中一样为产品定义完善的性能测试目标。因此,敏捷软件开发中通常采用的的性能测试目标为:保证应用的性能不会随着迭代的不断发生而变坏是一个非常好的实践。
表3 性能测试方法及其应用的领域
能力验证 | 规划能力 | 性能调优 | 缺陷发现 | 性能基准比较 | |
性能测试 | * | ||||
负载测试 | * | * | |||
压力测试 | * | * | * | * | * |
配置测试 | * | * | |||
并发测试 | * | * | |||
可靠性测试 | * | ||||
失效性测试 | * | * | * |
2.3 性能测试进行的时间
编码阶段,可在单元测试后,对函数、方法、在存储过程进行压力和并发测试,确认接口和被测对象能否健壮地处理极端情况,并且能否正确处理并发请求。这个阶段的性能测试是开发人员自行负责的。
编码-测试之间,可进行容量测试。在系统编码完成时,应该及时进行容量测试,确认系统能否满足在指定容量下的性能需求。
测试阶段,可进行负载、配置和基准测试。在进入测试阶段之后,在确保功能正确实现后需要进行负载测试,得到系统在当前硬件及软件环境下手性能指标,进一步形成性能数据基准,然后通过配置测试进行性能瓶颈的定位和优化。
2.4 性能调优的顺序
对于一个软件系统来说,从成本和难易度的角度来说一般的调优顺序如下:
- 软件平台设置:通过对服务平台的设置,可以更好地利用硬件资源,在不开销任何成本的情况下提升系统性能。
- 硬件平台:硬件的高估是最简单的,通过配置测试和基准测试可以很快地确定硬件更新带来的效果。
- 代码或SQL语句:通过静态分析得到负载较大的代码或SQL语句,将其进行修改,降低逻辑复杂度及成本开销。
- 架构或需求:在上述方法都无法完成性能高估时,需要考虑对架构进行一调整,由于调整架构所带来的影响和风险非常大,万不得已不会采取该种方法。为了避免出现最终发现性能瓶颈无法修复的问题,在设计初期就应该对架构进行科学的负载和并发测试,确定架构的正确性。
3. 常见的性能瓶颈
常见的性能瓶颈有如下一些情况:
- 硬件上的性能瓶颈:一般指的是CPU、RAM方面的问题,分为服务器硬件瓶颈、网络瓶颈、服务器操作系统瓶颈(参数配置)、中间件瓶颈(参数配置、数据库、web服务器等)、应该瓶颈(SQL语句、数据库设计、业务逻辑、算法等)
- 应用软件上的性能瓶颈:一般指的是应用服务器、web服务器等应用软件,还包括数据库系统。
- 应用程序上的性能瓶颈:一般指的是开发人员新开发出来的应该程序。
- 操作系统上的性能瓶颈:一般指的是windows/unix/linux等操作系统。
- 网络设备上的性能瓶颈:一般指的是防火墙、动态负载均衡器、交换机等设备。
4. 性能测试的步骤
- 测试需求测试计划阶段:测试需求分析、测试计划制定
- 测试设计测试开发阶段:测试脚本录制、测试脚本调试、测试场景设计
- 测试执行阶段:测试环境搭建、测试场景部署、测试场景执行
- 结果分析回测测试报告:测试结果分析、性能问题定位、测试报告评估
5. 性能测试工具及其原理
性能测试工具可大致分为服务端性能测试工具和前端性能测试工具两大类。服务端性能测试工具需要支持产生压力和负载,录制和生成测试脚本,设置和部署场景,产生并发用户和向系统施加持续的压力而前端性能测试工具则不需要关心系统的负载,只需要关心浏览器等客户端工具对具体的需要展现的页面的处理过程。目前市面上常见的商业性能测试工具(如loadrunner和silkperformance等)主要是服务端性能测试工具,侧重于产生负载,在给应用系统一定情况下观察应用系统的表现。前端性能测试工具的代表是firebug、yslow等,这些工具通过浏览器的接口,在浏览器展现和thgjweb页面时获利浏览器thgjweb页面时的信息,以让开发者和测试者能够通过某些针对web前端的改进,提高web应用的前端性能。
性能测试工具不能代替性能测试人员分析应用系统的性能,只能为测试人员提供分析的依据,如各项性能计数器的值、得到结果的返回时间等。测试人员可依据这些测试值,判断系统性能是否达标,或分析得到系统的性能瓶颈是什么等重要结果。
性能测试工具有商业工具和开源工具(如jmeter)两种选择。一般来说,创建或使用开源的测试工具能够开发出最适合应用的测试工具,可能拥有较低的成本,但学习成本一般较高,工具的稳定性和可靠性不足;商业工具稳定性和可靠性有一定保证,拥有更低的学习成本,但较低验证扩展其功能,很难与其他产品集成,总体拥有成本高。性能测试人员应该从实际需求(如测试系统运行平台、被测系统的通信协议、能否对使用的应用服务器进行监控等)出发,并结合考虑维护成本、项目活跃度、编程语种等因素慎重选择测试工具。
5.1 服务器性能测试工具
一般来说,性能测试工具包括以下部件:
- 虚拟用户脚本产生器(virtual user generator):可通过proxy,即中间人,实现。proxy接收客户端发送的数据包,记录并并其转发给服务端;接收从服务端返回的数据流,记录并返回给客户端。这样,虚拟脚本生成器能通过这种方式截获并记录客户端和服务器之间的数据流。之后,虚拟脚本生成器还需要根据录制时选择的协议类型,对数据流进行分析,然后,用脚本函数将客户端和服务端之间的数据流交互过程体现为脚本的语句。
- 压力生产器(player):用于根据脚本内容产生实际的负载。但产生负载需要耗用系统资源,可能需要多个PC机共同操作才能完成某个测试场景所要求的VU数。但多台机器之间如何产生“步调一致”的VU呢?答案就是使用“用户代理”
- 用户代理(agent):用户代理是运行负载机(load machine)上的进程,该进程与产生负载压力的进程或线程协作,接收调度系统的命令,调度产生负载压力的进程或线程。
- 压力调度和监控系统(conductor):是性能测试工具中直接与用户交互的主要内容,用户可通过其设定测试场景(如80个用户以脚本1的方式对系统进行访问,120个用户以脚本2对系统无师进行访问)
- 压力结果分析工具(analysis):压力结果分析工具可以用来辅助进行测试结果的分析,性能测试工具一般都能将监控系统获取的性能技术数器值生成曲线图,折线图等各种图表。通过展现性能测试过程中的各种参数指标,来供测试人员进行分析。
进行服务端性能测试时,需要选择测试脚本使用的协议。不合适的协议可能产生没有意义的脚本,或者录制的脚本无法修改使其适应其他的测试场景。如web应用的客户端和服务端之间通常是使用http/https协议,mail服务器通常使用smtp和pop协议等。
5.2 前端性能测试工具
浏览器的页面加载时间包括对html的解析,对页面上的图片、css等文件的获取和加载,客户端脚本(如javascript)的执行时间以及对页面进行展现所花费的时间。前端性能测试工具一般与浏览器紧密集成,通常以浏览器插件(如firebug)、浏览器钩子(httpwatch)或以浏览器的一部分(如chrome自带的开发者工具)等方式存在。前端测试工具能得到访问网站时发送的所有http请求、每个请求响应的时间以及请求发出的选择顺序等内容。