搞清测试对象
一个被测试的系统往往是复杂的,包含多个子系统和模块。性能测试的第一步是搞清楚测试对象。如果对测试的类型和规划没有搞透彻,就很容易搞不清楚真正的测试对象。
测试的对象一般叫做SUT(System Under Test),它可以是一段代码,一个模块,一个子系统或者一个整个的系统。比如要测试一个在线互联网服务的性能,那么这整个系统,包括软件、硬件和网络,都算是SUT。再比如,SUT也可以是一个子系统,比如运行在某台服务器上的一个进程。
搞清楚 SUT 的重要之处,是让测试做到有的放矢。除了 SUT 本身,其他所有的模块和构件在整个性能测试的过程中都不能有任何性能瓶颈。
比如测试一个在线服务,那么所使用的复制和流量模块就不能称为瓶颈。如果这一点得不到保证,那么性能测试得出的数据和结论都是不正确的。比如如果性能测试中负责产生负载流量的模块成为了瓶颈,一秒钟只能发出一千个请求,那么测出的吞吐量最多也就每秒1000请求。
决定测试的性能指标
搞清楚测试对象 SUT 之后,下一步就是决定具体的性能指标。
- 对一个面向终端客户的SUT而言,一个就是和客户直接相关的性能指标,比如客户(端到端)服务延迟。
- 如果SUT是系统中的某个模块,那么测试的指标有可能是资源的使用率,比如CPU或者内存使用率
平常用的最多的性能指标有三个:服务响应时间、服务吞吐量、资源利用率,这三个指标各有侧重,分布对应了终端客户、业务平台以及容量系统。通常,响应时间是用户关注的指标,吞吐量是业务关注的指标,资源利用率是系统关注的指标
决定测试指标的度量
决定性能指标后,还需要更加具体到统计上的度量。比如你关注的是平均值,还是百分位数(例如 P99);也或许是某个置信区间的大小。
举例来说,对服务响应时间延迟的指标而言,一般需要同时考虑平均值、中位数和几个高端的百分位数,比如 99 百分位。
决定性能测试的期望结果
SUT 和性能指标都确定了,那么下一步就是决定我们期望从测试中得出什么样的结论,比如是为了确认 SUT 的性能满足一定的指标呢,还是只希望获取一些性能数据做参考。搞清楚了测试的期望结果,才能决定什么样的测试结果是可以接受的,什么样是不能接受的。
假设 SUT 是一个互联网服务,测试指标是端到端的平均服务延迟。我们或许已经知道可以接受的平均服务延迟的最大值,比如 500 毫秒。如果性能测试测出的结果显示平均服务延迟是 600 毫秒,那么这个测试结果显然是负面的,就是被测互联网服务不够好,不能接受。如果只是想获取性能数据,那么这个 600 毫秒就是测试结果。
性能测试的规划
一次成功的性能测试离不开具体的规划,比如如下几个方面的重要内容,包括负载流量的特性、负载如何注入、测试的数据、黑盒还是白盒测试、测试的工具、测试的环境等。
- 负载流量的特征和测试类型直接相关。首先我们需要决定是用真正的生产环境的负载还是仿真的负载
- 负载如何注入:负载流量即使已经确认是真正的生产负载,还需要继续决定几个问题、
- 是用实时的流量呢,还是用过去捕捉的流量来重新注入?
- 流量的大小,是完全模拟生产环境呢,还是加大负载。
- 如果不使用实时生产流量,那么如何注入呢?
- 黑盒还是白盒测试
- 黑盒就是不改变 SUT,完全做被动观察
- 白盒就是允许改变SUT,比如在程序中输出更多的性能日志信息。白盒的问题就是改变了SUT的行为,可能导致最终得到的数据失真
- 测试工具:选择什么样的测试工具将取决于许多因素,例如支持的协议类型、许可证成本、硬件要求、平台支持等。
- 测试环境:
- 理想情况下,应该尽量用与生产平台相同的硬件、路由器配置、网络,甚至是网络背景流量等。
- 不过有时候我们会特意选取和生产环境不同的测试环境,比如当我们希望提高可重复性,降低测试环境的噪音;那么我们就会选取一个单独的不受干扰的环境来测试。
性能测试的执行
测试规划完毕后就是执行了,这个过程相对简单。
但是需要强调的是,测试结果的可重复性非常重要。性能测试和性能优化很多情况下是一个长期的行为,所以需要固定测试性能指标、测试负载、测试环境,这样才能客观反映性能的实际情况,也能展现出优化的效果。
很多性能测试比较复杂,所以不要期望一次测试就能成功让整个测试环境工作。经常需要实验好几次才能真正让整个测试环境搭配成功。
所以,复杂的性能测试需要多次迭代执行,一般有以下几种方式迭代:
- 分步进行:把复杂的测试验证过程分成几步,一次验证一步,最后一步是整个完整的测试。这样的好处是每一步的问题都可以及早暴露,快速解决
- 先短时间测试,再长时间测试:有些测试需要执行很长时间,比如一周。如果一周后才发现测试过程有错误,那就浪费了一周时间。所以,为了避免浪费时间,会先进行短期测试,比如半小时。然后分析结果,来发现其中的问题。这样可以比较快速地纠正测试中的错误。
- 模拟测试:在实际使用负载测试之前,先执行简单的负载测试以检查各种工具的正确性
分析测试结果
测试完毕,就需要分析测试结果了。
如果对一次测试的结果我们不满意,我们就需要重新回到以前的步骤上,或者重新执行测试的步骤,或者重新规划测试的方法。
为什么性能测试不容易一蹴而就呢?
这是因为任何测试,其实都依赖于很多其他模块,比如流量的产生、数据的注入、环境的搭建、干扰的排除、数据的收集、结果的稳定等,这些模块都不简单。所以寄希望于“毕其功于一役”,一次就完美地规划和执行一个测试,几乎是不可能的。
每一次测试完毕,我们都要认真分析一下结果,如果不满意,就需要看看如何改进。如果是测试方法不对,就需要重新规划。如果是环境不稳定,有干扰,那么就需要考虑如何消除干扰,净化测试环境。如果数据的收集不够多,就需要从测试模块中输出更多的信息。