连续性能回归101

文章作者:Travis Lazar

通过适当的计划和执行,持续的性能回归测试可以成为硬件和软件项目的强大工具,使服务器能够在整个服务器生命周期中支持数据中心的需求。

无论它们是云服务提供商、异地数据中心运营商,还是运行私有云的企业,数据中心运营商都有三个关键需求:可靠性、可用性和性能。开发能够在整个服务器产品生命周期内支持这些需求的服务器需要的不仅仅是简单的一次性测试。考虑到软件生态系统的不断变化的本质和数据中心中使用的软件的广度,需要一种多年的性能回归测试方法。

这可能会带来重大挑战。每天,数以千计的软件包向数据中心生态系统发布更新,这给硬件开发人员和数据中心运营商带来了技术负担,因为他们不一定知道自己的硬件或基础设施未来将如何使用。这一现实对开发社区来说是一个胜利,但它要求硬件开发人员在如何处理持续性能测试方面有一个宏观的方法。

性能回归测试的历史过程通常是静态的。一种非常典型的方法可能是开发一个shell脚本,输出性能结果,作为标准构建流的一部分运行测试,在构建时将结果与基线值进行比较,并基于该结果通过/失败测试。这有两个主要缺点:它只在构建时运行测试,用于确定通过/失败的基线值不太可能在整个测试生命周期中改变。要解决这个问题,要么需要对测试套件进行人工维护(这是昂贵且容易出错的),要么需要采用持续的性能回归技术。

连续性能回归测试是一种分析产品整个生命周期系统性能的方法。它涉及到从固件到用户空间应用程序的整个软件堆栈,解决了最广泛的应用程序配置范围。至关重要的是,它不仅测试初始配置,而且还继续测试随着时间的推移对生态系统的变化。

硬件和固件开发领域通常在自动化和持续开发活动方面落后于现代软件社区。这通常是由于开发单代硬件以及大量遗留流程和工具所花费的时间。

当应用于硬件和固件测试时,持续的性能回归测试和分析为系统在各种软件部署下的行为提供了有价值的见解。这些信息对于优化工作负载和维护数据中心操作员和终端用户所需的可预测的软件环境至关重要。因为像这样的裸金属测试是一项非常复杂的任务,涉及数以千计的活动部件,我们将讨论一些我们在这一过程中获得的宏观见解,包括陷阱和如何避免它们。这些经验教训可以应用于任何利用现代DevOps技术的软件项目。

连续性能回归101

我们将连续性能回归测试定义为以连续和不确定的节奏反复评估每个工作负载的性能。这里的性能度量是在一个完全集成的环境中完成的,这意味着我们使用整个硬件和软件堆栈进行测试。这意味着,许多组件中的一个可能会在测试运行之间发生变化。这些更改可以来自固件、操作系统、内核、库或其他组件(参见图1)。

软件栈的核心元素
图1:用于连续性能回归测试的软件栈的核心元素包括固件到使用用户空间应用程序运行的工作负载。

然后,每个结果为后续的每个结果提供一个比较点。目标是提供可操作的信息和可操作的工作流程:

•绩效是否发生了消极的变化(倒退)?

•绩效有积极的改变(改善)吗?

•变更有问题吗?如果是这样,该问题如何重现以使团队能够调试该问题?

•改变是有益的吗?如果是这样,我们可以从中学到什么并应用到其他领域?

这里软件堆栈的深度意味着我们可以看到大量的变化。测试每一个单独的提交或版本更新是不实际或没有用的。我们有效地“尽可能频繁地”测试,并在特定的时间点收集信息。这允许我们在进行根本原因分析时使用二分法。我们收集数据的次数越多,找出根本原因的过程就越容易。我们的测试每天大约运行6次,因此发生退步更改的窗口时间大约是4个小时。

我们的测试过程要求系统为每个测试重新构建。这确保了结果的完全再现。

图2显示了一个从开始到结束的典型测试流程。

CIDR测试过程
图2:这个过程生成一个滚动的结果集,这些结果会在一天内多次被捕获(参见图3)。

您将注意到,这是验证生态系统软件性能的一种散弹枪方法。虽然更具体或更有针对性的方法可能是首选,但世界上没有足够的计算或人力来测试堆栈中的每个软件排列。最好将测试过程看作类似于创建视频的过程——以足够的频率拍摄照片——以将性能视为一个动态过程。如果出现问题,可以用慢镜头重新拍摄,以捕捉更多的细节。

特定更新对性能的影响
图3:特定工作负载的测试结果显示了特定更新(大点)对性能的影响。红点表示结果低于计算的回归阈值的点。(来源:安培)

成功测试的关键

从策略开始。

测试的有效性取决于它的设计。在获取任何数据之前,仔细考虑你的策略。首先要准确地理解您想要度量的内容,然后再往回追溯。例如,在测试内存带宽时,确保您没有涉及缓存,否则您将得到误导性的数据。

找出你想要测量的系统的哪些特征。确定哪些元素需要在运行之间保持静态,哪些元素可以(并且应该)在运行之间发生变化。好的计划意味着好的结果。

小心数据捕获。

持续性能回归测试的目的不仅是捕获回归,而且是帮助识别根本原因。如果您没有在测试周期中收集正确的信息,您可能会花费大量的时间来重现以前的结果。在调试期间捕获额外的git散列或其他版本信息来增加粒度是一个好主意。你不会使用你收集的90%的数据,但是比特很便宜——当你需要它们的时候,它们可以节省时间和挫败感。

我们在回归开源项目的性能时使用这种技术。我们每8到10个小时运行一次测试,而不是每次提交一次。这节省了相当多的计算周期。在这个测试过程中,我们捕获系统上每个库的提交散列和版本,这样我们就可以在需要时完全复制软件堆栈。然后,回归的调试过程变成对被测试的软件执行git平分。

确保你正在衡量的是你打算衡量的东西。如果不正确地捕获数据,那么最终调试的可能是一个不相关的问题。例如,考虑一个内存带宽测试(如流)。如果测试期间写入的内存块大小小于缓存,那么测试将部分评估缓存性能,而不是原始内存带宽。每个工作负载都有重要的配置要求;确保你在做尽职调查,并有意地获取数据。

解耦数据采集和分析。

有策略地设计测试,但要确保数据可以在初始捕获之外得到利用。换句话说,保留原始数据。捕获和维护原始数据将支持事后更丰富的分析级别。

在一个工作负载中,我们发现Ubuntu的运行速度是CentOS的两倍。我们将完整的内核配置和软件设置作为原始数据提供,并通过在测试时从系统中提取的不同OS发行版配置进行了一系列研究。然后,我们将这些研究带入裸金属系统,以验证我们的不同假设。通过将分析转移到系统外的原始数据,并将其自动化,我们节省了数天的工程工作和系统时间。将这些节省的时间在数百个工作负载上相乘,你就会以一种非常积极的方式影响你的日程安排。

记录和控制系统配置。

众所周知,在度量性能时,硬件配置非常重要。在笔记本电脑上收集的性能结果与在顶级服务器平台上收集的性能结果非常不同。在相同CPU和平台的部署中甚至存在差异。内存配置和速度将影响内存性能,存储技术将影响I/O性能,许多调优因素将影响计算性能。这都是与您所测量的工作负载配套的已部署和测试配置相关的。

只有倒退和比较与“喜欢”系统。这意味着不同的测试程序会有所不同,但我甚至会要求每个主要硬件组件的完全相同的模型/SKU/版本。我们通常不会比较两个系统之间的回归结果,其中的任何主要硬件组件在这些关键领域是不同的。

创建一个标准化的考试格式和语言。

当然,如果不能重现结果,就不能调试问题。这不仅包括测试工具和系统配置,还包括返回和解释结果的方法。在不同的测试库中,解析结果的方法可能有很大的不同。交流工作负载标志可能变成电话游戏,在信息从一个工程师传递到另一个工程师时,信息会丢失。

在做性能调试的工程师之间,这样的交流是很常见的:

fio -filename =devicename -direct =1 -rw =randread -bs =4k -ioengine =libaio -iodepth =256 -runtime =120 -numjobs =4 -time_based -group_reporting -name =iops-test-job -eta-newline =1 -readonly

这个命令行是特定的,将生成可重复的结果。但是,它很神秘,不适合数据库存储或易于比较。

我们设计了一个解决方案,为开源的Phoronix测试套件创建了一个扩展,称为Phoronix测试扩展。这些是与phoronix兼容的测试,它们永不改变,易于通信,可以存储在数据库中,并以标准化格式显示输出,便于统一处理。这种方法简化了过程,并显著提高了结果的质量和可靠性。

例如,上面的FIO命令行可以打包在与phoronix兼容的测试中,称为ptx - io - fio randread - 4 k - libaio iod256 - 000001,它被编码到源代码存储库中,可以从该存储库中引用并运行它。因为这个测试与Phoronix测试运行程序完全兼容,所以它可以在任何Phoronix运行的地方运行,这使得它非常便携和灵活。它还输出一个标准的composite.xml结果格式,就像Phoronix测试运行器中定义的那样——使得库中的任何测试结果都是统一的,并且可以解析的。

不要错过轻度/中度的性能变化。

在处理持续的性能回归活动时,另一个可能被忽视的陷阱是人们经常致力于性能改进的现实。在硅开发中尤其如此,性能是最重要的因素之一。这意味着在软件堆栈或生态系统中完成工作时,性能回归的基线需要转移。

假设您为一个工作负载收集了大量数据,并且对基线结果有很高的信心。在这一年中,你的团队会逐步提高绩效。这在客观上是好消息,但潜在的陷阱是,它产生了一个缺口,可以隐藏仍然高于基线的回归(参见图4)。

测量与预期性能
衡量与预期性能
图4:测量与预期性能的图表展示了一个显著的回归(底部15%)是如何隐藏在基线之上的。

图中的红线表示在项目开始时设置的性能回归基线(失败标准)。顶部的图表显示了在开发的第一年(到12月)中显著的性能提升。底部的图表显示,在新的1月份,业绩出现了大幅的回归。然而,基线标准不会将其标记为回归,因为标准没有考虑到在开发的一年中增量的性能改进。

手动调整性能基准标准的成本很高,而且容易出错。我们的内部系统会根据收集到的每一个结果自动调整基线。它收集的测试结果越多,系统就变得越智能。

请记住,测试过程会影响系统性能。

在性能测试中,度量过程本身会影响结果,这是一个不幸的现实。捕获系统数据(如时钟频率、活动进程和CPU利用率)会消耗系统资源,从而降低某些(但不是所有)配置中的工作负载性能。对于不小心的人来说,这可能导致浪费时间去追逐虚幻的回归。

解决方案是从性能度量过程中抽象出硬件监控过程。例如,您可以为每个配置执行四个测试运行。在性能回归分析中使用前三个数据集。第四次运行将测量硬件行为。第四次测试的结果将严格用于提供系统测量信息,而不会用于回归分析。

制定有效的、标准化的报告。

如果结果没有以可操作的方式呈现,那么最好的测试基础设施是无用的。糟糕的数据科学实践很容易歪曲性能或模糊模式。尺度不一致和非零的数据图会妨碍比较。只显示一次运行的变化而不显示方差也可能是有问题的或误导的。有些测试是高度一致的——1%的增量是巨大的。对于其他情况,±2%是正常的运行偏差。数据表示必须使这些差异易于在上下文中检测到。

连续的性能回归测试产生的大量数据需要一种简单的可视化结果格式。我们建议使用每个人都要使用的标准化性能回归报告。这集中了数据科学的最佳实践,并创建了每个人都熟悉的一致的视觉语言。

不具有可操作性的数据不值得关注。

结论

持续的性能回归测试在软件开发人员中非常有名,特别是在web开发领域。它也可以是硬件或较低级别软件项目的强大工具。软件开发人员所接受的大多数现代开发实践并没有在硬件开发中得到广泛的实践。

测试结果仅与测试本身的计划、过程和执行一样好。应用我所描述的技术将使您对潜在的陷阱保持警觉。

留下你的评论