科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道评论专栏: Joey Bernal:再谈有关性能的基础知识

评论专栏: Joey Bernal:再谈有关性能的基础知识

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文介绍了您在开始对性能进行测试或者优化之前,需要了解的一些基础知识。本文不仅可以作为初学者的入门读物,还可以帮助其他读者巩固相关的知识。

作者:ibm 来源:ibm 2007年10月6日

关键字: 应用 技术 3977 中间件

  • 评论
  • 分享微博
  • 分享邮件

关于性能的考虑

最近,我一直关注门户性能,并帮助我们团队中新的顾问了解如何处理和考虑性能方面的问题。在我看来,这涉及到从如何为门户项目和环境处理性能度量以及容量规划的角度来考虑端到端的问题。在完成这项工作的过程中,考虑整体方法和途径与了解如何解决特定问题是同样重要的。当然,当您在面临处理复杂问题的压力的时候,一切都很难说。

在这个专栏中,将谈论我所研究过的一些随机主题,这些主题可能可以帮助您更好地了解在性能测试过程中所发生的情况。尽管本文只涉及到一些很浅显的内容,但是为初学者提供了关于一些基本性能主题方面的简要介绍,并可以帮助其他读者及时复习性能方面的基础知识。





回页首


性能方面的术语

对于理解和说明性能度量的基础知识来说,Performance Analysis for Java Web Sites 是我最喜欢的参考资料之一。最近,有人问我是否认为这本书已经过时了,因为这本书从出版到现在已经有好几年时间了。但无论如何,其中的信息在今天和在数年前一样是有效的。这些基础知识并没有发生改变(当然,有一些工具发生了改变),为了与顾客交流,并在我们内部交流,掌握一定的基础知识是非常重要的。

我尽量在术语方面很好地保持一致,并可能会在特定的性能情况中一次又一次地重复它们。通常在一两天之内,每个人都开始使用相同的术语了。我并不打算对其进行过多的简化(其中的内容,远比我在这里所能描述的要多),但是有三种特定的度量,它们可以通过合适的词汇帮助巩固您的观点。对于刚接触性能术语的人来说,常常会将它们弄混,或者对其含义有不同的理解。让我们来澄清下列术语:

  • 负载是网站所承受的压力总量。它始终会使我想到软水管,可能已经关闭,只能细细地流出水滴;也可能打开到了最大,让水流奔涌而出。对于网站,我们常常从并发用户的角度来讨论负载问题,这并不一定意味着每个用户都在完全相同的时刻请求某个网页,这其实是一种常见的误解。最好是在一定的时间范围内来考虑负载问题;例如,在特定的时间范围内访问该站点的用户数量,也许是以五分钟作为时间间隔,也许是每小时。

  • 响应时间是门户或者站点对请求做出响应所花费的时间。从浏览器的角度来看,这是真正的端到端的时间,并且通常不包括浏览器生成或显示页面所花费的时间。可以考虑到,随着站点负载的增加,响应时间通常将会发生变化(它可能会增加),最终可能增加到用户无法接受的情况。响应时间是一项受到普遍关注的度量,而您的最终目标是对门户进行优化,以便在预期的用户负载情况下,提供一致的响应时间范围。响应时间目标需要遵循相关的行业标准;例如,站点的目标可能是在五秒钟内响应 95% 的页面请求。

  • 吞吐量是门户响应请求的速率。通常,我们将其视为系统的点击率或者页面速率,并且页面速率度量更加合适。吞吐量,再加上响应时间和用户的活动模型,能够帮助您确定您的系统在给定的时间范围内可以处理(负担)多少用户。通常,吞吐量的测量是相对于负载情况的,确定随着用户负载的继续增长所出现的系统边界。

这三个主要的术语相互关联在一起,可以帮助您开始了解门户的运行情况。(请参见参考资料,以获得关于这些性能术语,以及其他性能术语的更多信息。)





回页首


模拟用户行为

可以使用负载生成器所运行的脚本对用户行为进行模拟。负载生成器启动一些虚拟用户 (vusers),并且通过所编写的脚本来运行每个 vuser。确定用户将如何访问和使用站点,这大概是性能评估过程中最具挑战性的部分之一。通常,您根本不知道用户将要做些什么,或者他们以怎样的频率来访问该站点,因此有些时候,它真的是让人难以猜测。

在构建新的门户以替换现有的网站时,您常常可以查看现有的分析结果,以尝试和了解用户的行为习惯。然而,仅仅这样做是不够的,因为您期望随着新的门户的使用,将带来使用率的增长;您希望,在用户发现该门户为其日常生活所带来的价值之后,将像蜜蜂看到了蜂蜜一样,立刻蜂拥而至。的确,有些时候,完全可以从现有分析结果所提供的信息开始,但是我们常常需要考虑到最坏的情况,以确保该门户能够处理任何可能的负载。实际上,我有时候宁愿过高地估计预期的用户负载,因为这样一来,当该站点投入使用时,它将能够轻松地应对各种情况(虽然要使得该站点达到这些负载值通常需要付出极大的努力)。如果过低地估计了负载,或者根本没有执行任何测试,那么情况将会非常糟糕。

请多花些时间考虑用户可能在您的站点中进行哪些操作,并对最糟糕的用例场景进行模拟,以注入到测试过程中。如果您是设计团队的成员,那么您很可能对自己的门户熟视无睹,并且无法找出哪些内容对最终用户来说是重要的。用户接受度测试是项目生命周期中的一个部分,在这个过程中可以为项目注入新的观念,但是有些时候,这项工作在生命周期中开展得太晚,以至于无法真正地起到作用。可以考虑在设计周期的早期,请求来自外部人员的输入,以帮助您了解用户可能做出的选择。对于最糟糕的情况,请确保包括下列常见的事件:用户不退出站点、大量的下载或者上传、复杂的搜索查询、复杂报告的生成等等,因为它们都有可能出现在您的站点中。

思考时间是对用户行为模拟的另一个方面。在实际中,在页面请求之间,用户往往需要花费几秒钟的时间,可能是在阅读面板上信息、填写表格、或者决定下一步该做什么,等等。因此,您可能需要对一些用户进行模拟,以便迅速地转到某个特定的页面,然后花费更多的时间来执行某种操作(作为其工作的一部分),或者您可能使用户在输入搜索请求之前,在主页上逗留几秒钟。在通过脚本运行虚拟用户(稍后将详细介绍这一内容)的同时,负载测试生成器将思考时间纳入考虑范围。一项通用的规则是,增加思考时间将减少生成器在系统中生成的负载,减少思考时间将缩短完成用户脚本所需的时间,从而增加整体负载。





回页首


简单的计算

我前面提到了吞吐量和页面速率如何为您将要运行的许多性能测试提供一致的度量。查看吞吐量的其他方式,如点击率或者请求速率,可能相互混淆,因为人们常常以不同的方式来考虑它们。一个页面通常由大约几十次请求(点击)(因为浏览器需要逐个地下载图像)以及嵌入该页面的其他静态组件组成。最终用户并不真正关心这种方式的点击。获得一半的页面并没有什么意义,只有在获得了整个页面后,用户才会感到满意。测量页面速率可以帮助您摆脱混淆,并且使您更清楚地了解门户中所发生的情况。

大多数度量在计算上都很简单,但是它们通常取决于多种因素,而这些因素可能根据服务器的负载和响应时间发生改变。让我们以基本的每秒页面速率的计算作为开始,然后看一个示例。基本计算如下所示:


图 1. 通用的每秒页面请求速率的公式
图 1. 通用的每秒页面请求速率的公式

要使用这个计算,您需要掌握一些关键的值。首先是在给定时期内访问该服务器的预期用户数量;这就是您对该门户所施加的负载。例如,假设您有 45 个用户(或者 vuser,视情况而定),这些用户可以在 5 分钟内运行脚本。那么可以得到下列信息:

在 5 分钟内有 45 个用户 = 45 * 12(一小时中有 12 个 5 分钟)= 一个小时内有 540 个用户

如果每个虚拟用户都通过脚本访问 8 个页面,那么您可以确定具体的页面速率:


图 2. 每秒页面速率的示例
图 2. 每秒页面速率的示例

您如何确定思考时间呢?通常,这是用户将要执行的任务中的一项重要的内容。虽然您希望在测试中尽可能地尝试并模拟用户的行为,但是有些时候,您需要根据技术上的限制对其进行适当调整。例如,如果您认为系统中可能会有 100 个用户,但是负载生成器只提供了 50 个虚拟用户,那么您通常可以调整测试或者减少思考时间(以便从数学上应用所需的用户负载)。根据可用的虚拟用户的数量,以及该站点的平均已知响应时间,您可以发现:


图 3. 通用的思考时间计算
图 3. 通用的思考时间计算

为了帮助您计算所需的思考时间,以便您可以对该站点实现足够的负载,我们假设存在下列值:

  • 每个页面请求的平均响应时间:3 秒
  • 吞吐量:每秒 21 个页面
  • 可用的虚拟用户: 120

结果:


图 4. 思考时间计算的示例
图 4. 思考时间计算的示例

要实现这种类型的负载,在各个页面请求之间,您需要平均 2.7 秒的思考时间。其中,您也许发现了一个有趣的地方:对于 120 个虚拟用户和 3 秒的响应时间,您无法测试高于每秒 40 个页面的速率。

另一种方法是,根据系统中的每秒页面速率(如果已知的话),估计系统可以处理的用户数量。


图 5. 通用的用户负载公式
图 5. 通用的用户负载公式

可以考虑这种情况,一个站点平均每秒处理 25 个页面请求。在进行一番思考之后,您估计出每个用户在进入门户的时候将访问 14 个页面。在此基础上,您能够确定系统在给定的时间范围内可以处理的用户数量:


图 6. 用户负载计算的示例
图 6. 用户负载计算的示例

我们希望,在为您的测试场景确定一些相关的参数时,您可以使用这些计算以及其他计算。使用其中的某些公式以获得您所需的其他值,这是非常容易的。(请记住,需要在秒和小时之间对您的数据重新计算,这取决于结果所面向的受众。)





回页首


关于垃圾收集的内容

正如您可以想象的,内存耗尽是一件很糟糕的事情。要了解内存耗尽对您的系统所产生的影响,也是非常简单的:所有的工作都将停止。通常当服务器耗尽内存时,首先需要考虑的是内存泄漏,但实际上最有可能的是,您的应用程序刚刚使用了大量的内存。如果在删除负载之后,系统不能够恢复所使用的内存,那么我们就确定发生了内存泄漏。对于内存泄漏的一个简单测试是,在某天的最后一次测试之后让系统继续运行;如果到第二天,该系统恢复到了原始状态,那么您通常可以排除泄漏。如果您能够在测试周期中将这种方法的使用作为一种习惯,那么您将可以看到,在没有进行测试的时间段内,代码更改是否引入了泄漏。

但如果不是内存泄漏,而您的应用程序正在使用大量的内存,那又该怎么办呢?

当出现内存分配失败的时候,通常将启动垃圾收集 (GC)。GC 对于测量 JVM 中内存使用情况来说是非常重要的。尽管实际上只是简单的一组数据,但它是可以在服务器上获取的关键度量的其中之一。(要收集关于内存使用情况和垃圾收集的信息,请在您的应用服务器中打开详细的垃圾收集日志记录。)然而,过于频繁的垃圾收集可能、并且将会对您的应用程序的性能产生反作用。将用在垃圾收集上的时间除以进行测试的总时间,这样可以让您大致地了解在垃圾收集工作上花费了多少时间。例如,如果您的详细垃圾收集日志的分析结果指出,在一个小时内总的垃圾收集的时间是 1402119 毫秒,那么您可以确定下面的内容:

1402 秒 / 3600 秒 = 39%(一个小时内花费在垃圾收集上的总时间)

结果数值越小,表明您的系统的优化程度越高。一项好的指导原则是,尽量使得在垃圾收集上花费的时间少于 10%,但不要让这个数值成为您的环境中必须实现的“硬性指标”,因为还需要考虑到其他因素:

  • 繁重的垃圾收集

    了解您的系统将多少时间花费在垃圾收集上,这是很有必要的,但是将过多的时间花费在垃圾收集上将会对系统的性能产生怎样的影响呢?这里提供了一个示例,该示例说明了在真实的情况中,繁重的垃圾收集对系统产生的影响。

    图 7 显示了测试期间,在负载和垃圾收集情况下的系统的结果。这个测试相当简单:通过脚本模拟在数秒之内相互请求的三个页面,并且负载生成器将在大约一小时的时间内遍历数千个用户。



    图 7. 繁重的垃圾收集示例
    图 7. 繁重的垃圾收集示例

    该脚本所耗费的垃圾收集时间缓慢上升,但是很快开始占用许多内存,并生成了大量的瞬时对象。当新的请求到来时,内存分配将会失败,通常使用 GC 来为新的请求腾出空间。

    图 8 中显示了该测试的结果。整体响应时间是 1.4 秒,并且标准偏差小于 2 秒。最大的响应时间超过了 27 秒,这对于那些不得不等待很长时间的用户来说,可能是痛苦的经历。该测试可能请求的页面总数为 95,000。



    图 8. 繁重垃圾收集的页面概要
    图 8. 繁重垃圾收集的页面概要

    图 9 中显示了单个页面的响应分类,其中的数据和前面的整体概要完全一致。该测试脚本完成了以下这些页面请求:

    1. 装载初始登录页面。
    2. 登录,并显示主页。
    3. 请求 MyWorkplace 页面。


    图 9. 繁重垃圾收集的性能概要
    图 9. 繁重垃圾收集的性能概要

    在经过测试的应用程序中,其主页和 MyWorkplace 页面都显示了大量自定义 Portlet,它们用于从后端数据库中获取相应的数据。您可能会注意到,在这个脚本中没有退出操作。在许多测试场景中,这是很常见的,允许用户数据挂起在内存中,直到用户会话超时,或者直到刷新正在使用的任何缓存。通常这更符合现实的情况,用户可能只是简单地关闭他们的浏览器,而不是严格地退出。

  • 增加一些空间

    现在,让我们来看看完全相同的测试的另一次运行。这里,您可以发现,整体 GC 所占的百分比远远低于前面的示例。这可能是由于以下几项操作之一所引起的:

    • 或许您可以在 JVM 内增加可用的内存。通常可以采用这种方法作为开始,但是在某种情况下,它可能变得毫无作用或者不可能实现,如果您不断地为 JVM 增加可用内存的话。
    • 另一种方法是在代码自身内部执行一些优化,以减少该应用程序所使用的内存量。


    图 10. 少量垃圾收集示例
    图 10. 少量垃圾收集示例

    (在产生该信息的实际测试中,我的确可以将比率再增大一点,但是我认为可能会在负载生成服务器中碰到 CPU 的限制。您肯定希望在测试运行期间注意这样的情况。)

    在图 11 中,整体的平均响应时间下降了一半以上,并且标准偏差低于 1 秒。这在性能上是非常显著的提升,并且清楚地说明了,JVM 中过多的 GC 可能会对性能产生负面的影响。



    图 11. 少量垃圾收集的页面概要
    图 11. 少量垃圾收集的页面概要

    显然,单个页面时间同样得到了改善。不仅减少了平均值,还将标准偏差减少到了 1 秒钟以下。



    图 12. 少量垃圾收集的性能概要
    图 12. 少量垃圾收集的性能概要

    图 12 中还有另外一个内容需要注意,即此次运行的“每秒”速率。请注意,与前面的测试相比,它大约每秒多了 3 个额外的页面。在多个服务器中实现这种小幅度的性能提升,那么则可能为数十(或者数百)个更多的用户提供服务。这一点真实地说明了过多的 GC 可能会对性能产生怎样的影响。





回页首


标准偏差又是怎么回事呢?

在前文中我多次提到关于垃圾收集的标准偏差,并且在评估性能结果的时候,人们常常会忽略它。事实上,最近我和一个同事讨论了关于标准偏差的重要性,以及它常常被人忽视的情况。标准偏差,通常使用小写的希腊字母 sigma 或者 σ 来表示,它可以帮助您从整体上了解测试工作中所发生的情况。标准偏差真正能够告诉您的是,某些用户是高于还是低于平均测试水平(或者算术含义)。

正态分布数据认为,样本中约 68% 的数值分布在距离平均值为 1 的标准偏差之内。附加的标准偏差可能在分析结果中带来更高的百分比或者置信度。其中的一些置信区间如下所示:

标准偏差
σ 68.26894921371%
95.44997361036%
99.73002039367%

在测试运行期间考虑可能生成的负载时,2σ 通常是足够接近的。

作为一个示例,请再次查看图 12 中有关登录的值。使用平均值和标准偏差,您可以说明,68% 的尝试是在 0.2 秒到 1.3 秒之间。这是很重要的,因为它说明了,仅查看平均值是不够的,特别是当您的标准偏差非常大的时候。这表明,平均值并不能真正地说明有多少用户获得了适当的响应时间。他们中的某些人可能很快地收到了答复,但是相当数量的用户则需要等待很长的时间才能收到答复,并且其等待时间可能超出了您的预期值。

事实上,计算标准偏差可能有点麻烦,但幸运的是,许多性能工具可以帮助您完成这个任务。即使您的工具并没有提供这些结果,但通常,您可以将原始数据转储到电子表格中,并使用公式对其进行计算。通过两个标准偏差,可以使您更清楚地了解相关的结果,尽管许多工具并没有提供这种信息,但幸运的是,可以非常容易地得到这个结果。





回页首


结束语

随着性能测试工具变得更加智能化,我们从获取相关性能数据所需的大量手工工作中解放了出来。而且,了解一些性能基础知识可以帮助您扩大自己的知识面,并且可以帮助您更好地理解和表达所提供的结果,这一点是非常重要的。如果您的工具没有为您提供所需的结果,并且必需进行一些手工的干预,那么但愿本文中的这些信息能够提供很好的起点。

我希望提到的是,我并不认为自己是性能方面的专家。也许我比其他人知道的稍微多一些,但是与性能方面的专家相比,我还有很长的路要走。老实说,我并不确定自己是否将专攻性能方面的问题,因为这个领域中发生了很多的变化。我要说的是,对于那些希望改进他们正在实施和负责的项目的普通专业人员来说,对性能测试和分析有基本的理解,这是非常重要的。我们都应该努力深化这个领域中的技能,并继续提高全面的知识体系。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章