9月7日-8日,相约 2023 腾讯全球数字生态大会!聚焦产业未来发展新趋势! 了解详情
写点什么

我从性能测试中学到的那些经验与教训

  • 2019-12-11
  • 本文字数:3362 字

    阅读完需:约 11 分钟

我从性能测试中学到的那些经验与教训

本文要点:

  • 要做好性能测试很难,但花一些额外的时间做好性能测试是值得的,这样可以避免一些反复出现的问题;

  • 要注意区分延迟测试和吞吐量测试,因为它们是系统的两个不同的方面;

  • 在进行延迟测试时,要把吞吐量固定在一个水平;

  • 在进行聚合时不要丢弃任何一个与性能有关的信息,要尽可能多地把它们记录下来;

  • 只要多加小心,再加以自动化,就可以最大程度地避免出现性能回退。


对于像 Hazelcast 这样的内存计算平台来说,性能意味着一切。因此,我们在性能方面投入了大量精力,并在这个方面积累了多年的经验。


在这篇文章中,我将介绍一些常见的问题,并分享如何做好常规的性能测试。

性能测试中反复出现的问题

首先,测试环境差异是最常见的一个问题。如果一个系统最终要被部署到多台具有超强处理能力的机器上,那就不能够只根据在本地开发机上进行的性能测试做出合理的假设,因为在将系统部署到真实的环境中,结果会完全不一样。有趣的是,人们比他们自己认为的更容易犯这种错误。在我看来,其中的主要原因是懒惰(在本地测试很容易,但搭建额外的测试机器需要时间),意识不到这会成为一个问题,有时候是因为缺乏资源。


另一个反复出现的问题是测试场景不真实,例如,负载不够高、并发线程太少,或者完全不一样的操作比率。通常来说,在测试时要尽可能接近真实场景。也就是说,在开始测试之前,我们要尽可能多地收集与测试、用例、测试目标、环境和场景有关的信息,尽可能做到与真实环境相似。


下一个问题是不区分吞吐量测试和延迟测试,有时候甚至不确定是不是真的关心这两种测试。从我的经验来看,客户通常会更关心应用程序的吞吐量,于是他们就尽可能压榨系统的吞吐量,并基于这些结果做出决策。但如果你深挖下去,你会发现,在 99%的场景中,他们的负载都只是介于每秒多少个操作之间。在这个时候,可以把系统的吞吐量固定在这个水平,然后观察延迟,并进行延迟测试,而不是吞吐量测试。


最后一个问题是只关心聚合指标,比如均值和中值。这些指标把很多信息隐藏掉了,而这些被隐藏的信息很可能有助于做出更好的决策。本文的“评测性能”一节将更详细地介绍应该要收集哪些信息。

延迟测试和吞吐量测试之间的区别

吞吐量基本上是指某段时间内完成的操作次数(通常是每秒多少次操作)。延迟,也就是响应时间,是指从执行一个操作开始到接收到结果之间的时间。


这两个最基本的指标之间通常是相互关联的。在非并行系统中,延迟与吞吐量是成反向关系的,反过来也是一样。简单地说,如果每秒可以完成 10 个操作,那么每个操作(平均)需要十分之一秒。如果每秒种完成的操作越多,那么每个操作需要的时间就越少。


但是,在并行系统中,这种关系很容易被打破。以在 Web 服务器中增加线程为例,这样做不会缩短每个操作的响应时间,也就是说延迟不变,但吞吐量却提升了。


因此,吞吐量和延迟实际上是系统的两个不同的指标,我们要单独测试它们。更确切地说,在进行延迟测试时,我们要把吞吐量固定在一个水平,例如,“在每秒钟 10 万个操作的前提下测试延迟”。如果不这么做,在不同的吞吐量下系统延迟会发生变化,也就失去了可比性。


我们得到的经验教训是:在进行延迟测试时要使用固定的吞吐量。

收集和比较性能测试结果

另一个问题是如何收集、记录和分析性能测试结果。我觉得可以分为两个部分:一个是不要丢弃信息,一个是把分散的点连接起来。


我经常看到性能基准测试报告里会显示每秒平均操作数、中值或者延迟的某种百分位。的确,这样的报告看起来很简洁,也很容易发布出去。但是,如果你真的关心性能问题,就不要这么简单粗暴,你需要看到“所有”的数据。


在进行吞吐量测试时,一个常见的做法是讲总的操作数除以时间,这样做很容易就把重要信息丢掉了。如果你想要看到整体的情况,就需要显示吞吐量的变化过程。



从这张图可以很容易地找到问题所在。根据简单的“每秒平均 X 次操作”,你可以快速地得出结论:绿线是最好的。但是,这张图看起来又有点奇怪。虽然绿线的吞吐量是最大的,但是也是最不稳定的。换句话说,绿线抖动得很厉害,一点也不平滑。我们基于这条线发现了线程调度问题。


总的来说,这张图显示了吞吐量的变化过程,但如果只是从聚合结果来看,是不可能发现问题的。我们可能会因为绿线的值最高而欢呼雀跃,但却忽略了一个重要的性能问题。


在进行延迟测试时,另一个常见的问题是只显示平均延迟,或者好一点的话会显示某种百分位。在理想情况下,你可以创建一个百分位直方图,让你可以看到整体的情况。你还可以做得更好,就是查看百分位随时间的变化情况。


作为例子,下图显示了 50 百分位随着时间发生变化的情况。



从图中我们可以清楚地看到延迟随着时间的变化而增长。如果我们只发布平均值或者是一个完整的直方图,就很难发现这些信息。我们知道,系统发生了内存泄露。


Gil Tene 的HdrHistogram是一个非常好的用来生成百分位和延迟图表的工具。


然后是同时查看所有的图表。如果你在其中的一张图中发现了问题,要在另一张图中进行确认。如果有性能问题,通常会在多个地方体现出来。


我们再以内存泄露为例。如果一个 Java 程序发生内存泄露,我们会看到内存使用量上升,这个时候吞吐量应该会下降,因为垃圾回收会占用更多的时间。与此相关联的是,延迟也可能会增加。我们也可以看一下线程的 CPU 时间,它们的 CPU 时间也会减少,因为垃圾回收占用了更多的 CPU 时间。信息越多,你就会得到更好的结论,就越容易找到解决问题的方案。

找出性能瓶颈

找出性能问题的根源通常是一个漫长而痛苦的过程,取决于具体的代码、测试人员的经验,有时候甚至是运气。但我们仍然是有迹可循的。


首先是逐步诊断,每次只诊断一个步骤。在进行性能调优时,我们通常会说“这个选项很好用,这样设置垃圾回收对性能有帮助,打开这个开关可以获得更好的结果,我们都试试吧”。最终,这种叠加效果导致我们搞不清楚哪个才是有效的。因此,每一次我们只走一步,只使用一个开关,只修改一个地方。


具体来说,我们可以利用所有可利用的工具,特别是在手机数据的时候。你掌握的信息越多,就越是能够更好地了解系统行为,更快地找到痛点。因此,我们需要尽可能收集所有信息:系统息息(CPU、内存、磁盘 IO、上下文切换)、网络信息(对于分布式系统来说尤为重要)、垃圾回收日志、Java Flight Recorder(JFR)的分析数据,等等。我们还开发了专有的诊断工具,更细粒度地直接收集内部信息——操作时间取样、内部线程池的大小和时间、内部管道和缓冲区的统计信息,等等。



上图比较了三种调优选项的不同点,显示了每秒钟系统上下文切换次数。从结果看,绿线的切换次数最少,说明系统做的有用的事情更多,这个可以从吞吐量那张图中得到验证。

防止性能回退

进行常规(每天)自动化性能测试是很有必要的。在引入变更时需要尽可能快地获取必要的数据。在发现性能回退后,我们可以很容易将其隔离出来,极大减少用于修复回退所需的时间。


一个是执行测试,一个是保存和分析结果。在 Hazecast,我们使用PerfRepo,一个开源的 Web 应用程序,用于保存和分析性能测试结果。它会更新每一个最新的性能测试结果,所以很容易发现性能回退——你会在图中看到线往下走。我在 Red Hat 工作期间积极维护这个项目,因为时间原因,现在的开发进度慢了一些,但仍然是个完全可用的项目。


但不管怎么样,限制还是有的。我们无法面面俱到,因为各自情况的组合几乎是无限的。我们倾向于选择“最重要”的那些,但具体怎么做仍然值得我们讨论。

结论

要做好性能测试很难,很多方面都会出问题。关键在于要多注意细节,了解系统的行为,避免出现一些可笑的结果。当然,这需要时间。在 Hazelcast,我们也很注意这些,我们愿意为此付出时间和精力。你们呢?


作者介绍


Jiři Holuša是一个专注于开源的软件工程师,他热爱他的工作。之前在 Red Hat 工作,目前是 Hazelcast 质量工程团队的负责人。Hazelcast 是一家开发内存计算平台的公司。Holuša 喜欢深挖一个问题,从来都不放弃,直到问题得到解决。除此之外,他喜欢运动,作为一个真正的捷克人,他喜欢在喝啤酒时与别人进行愉快的交谈。如果你想看到更多由 Holuša 提供的有关性能测试的演讲,可以看他在 2019 年欧洲 TestCon 大会上做的Performance Testing Done Right演讲。你可以在 Twitter 通过 @jholusa 联系他。


原文链接


Lessons Learned in Performance Testing


活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2019-12-11 09:102215

评论

发布
暂无评论
发现更多内容

Nginx 如何将所有 HTTP 的流量转移到 HTTPS

HoneyMoose

【Go实现】实践GoF的23种设计模式:建造者模式

元闰子

Go 设计模式 建造者模式

聊聊 C 语言和 ABAP 这两门编程语言的关系

Jerry Wang

编程语言 C语言 SAP abap 5月月更

15-拦截器

爱好编程进阶

Java 程序员 后端开发

BATJ内部Java求职面试宝典,尤其应届生如果还没有学过那后悔去吧,也许你已经错过N多家大厂offer

爱好编程进阶

Java 程序员 后端开发

MySQL存储过程批量生成假用户电话号码

芝士味的椒盐

MySQL MySQL 数据库 5月月更

SpringSecurity认证流程分析

急需上岸的小谢

5月月更

50道大厂经典Spring面试题,你能答出来几题?

爱好编程进阶

Java 程序员 后端开发

企评家,打造专业的企业大数据SaaS平台

企评家

企业大数据 企评家 企业成长性评价

Django Model 如何返回空的 QuerySet

AlwaysBeta

django

IntelliJ IDEA 如何增加运行时候的内存

HoneyMoose

Docker下的Spring Cloud三部曲之一:极速体验

程序员欣宸

Java Spring Cloud 5月月更

MongoDB 入门教程系列之二:使用 Spring Boot 操作 MongoDB

Jerry Wang

node.js 数据库 mongodb 分布式数据库 5月月更

MongoDB 入门教程系列之三:使用 Restful API 操作 MongoDB

Jerry Wang

数据库 mongodb 分布式数据库 分布式数据库mongodb 5月月更

10-2 5-2 查询至少生产两种不同的计算机(PC或便携式电脑)且机器速度至少为133的厂商 (20 分)(思路加详解+测试用例

爱好编程进阶

程序员 后端开发

2个不同的对象集合如何取交集和差集

爱好编程进阶

Java 程序员 后端开发

apk瘦身;如何缩小体积呢?这篇文章来教你

爱好编程进阶

Java 程序员 后端开发

CleanMyMac2022免费版Mac电脑清理软件功能

茶色酒

CleanMyMac2022 CleanMyMac

Nacos源码系列—关于服务注册的那些事

牧小农

源码 nacos

从零构建物联网平台-给个理由先

老任物联网杂谈

物联网平台

网站开发进阶(二十六)JavaScript 实现页面刷新方法汇总

No Silver Bullet

JavaScript 页面刷新 5月月更

C语言_Linux基本命令与C语言基础

DS小龙哥

5月月更

2021-6-1【利用指针方法求数组的最大值和最小值】

爱好编程进阶

Java 程序员 后端开发

聊聊 Kafka:Kafka 消息丢失的场景以及最佳实践

老周聊架构

kafka 4月月更 5月月更

《对线面试官》Java注解

Java3y

Java 程序员 面试 编程语言 5月月更

用户行为分析模型实践(二)—— 漏斗分析模型

vivo互联网技术

大数据 数据分析 Clickhouse

AQS中那些不得不说的理论知识

爱好编程进阶

Java 程序员 后端开发

虎符交易所上线量化网格交易 同步开启活动三重奏

区块链前沿News

活动 虎符交易所

Flutter/Dart:生成最小值和最大值之间的随机数

坚果

5月月更

2021 年最新版 68道Redis面试题,20000字,赶紧收藏起来备用

爱好编程进阶

Java 程序员 后端开发

320000字2021春招高频面试真题汇总

爱好编程进阶

Java 程序员 后端开发

  • 扫码添加小助手
    领取最新资料包
我从性能测试中学到的那些经验与教训_软件工程_Jiří Holuša_InfoQ精选文章