您的位置:首页 > 其它

性能测试专题-新手误区

2013-02-26 16:08 211 查看
1、找不到测试点,不知为何而测

有过一些性能测试经验的人很容易进入此状态,他们已经熟悉了性能测试的基本流程,能够比较熟练的使用测试工具开展工作。我大概从事性能测试一年左右时遇到了这个问题,那时我觉得性能测试的过程没有太多挑战,遇到的每一个系统,仿佛都可以用同样的流程完成。半天时间填写测试方案,一天时间来准备测试环境,一天时间准备测试脚本,一到两天来完成各种测试用例(基准测试、日常压力测试、峰值压力测试、绝对并发测试、稳定性测试等),然后就是调优、问题复测和完成测试报告。在我看来,性能测试好像变成了用一些工具去执行一个个固定的用例。

  这样的工作持续了一段时间后,我感到有些不对劲,一定是哪里出了问题。性能测试难道真的这么简单,简单到把任何一个系统套入标准的流程中就可以了?于是我开始思考测试的意义,为什么要进行性能测试?是因为性能测试可以提供关于瓶颈、缺陷、效率等等我们认为有价值的信息。那仅仅通过一个工具,或者是一个固定的流程,就可以发现不同系统的这些信息么?这显然是不可能的。

  我开始尝试尽量深入的去理解被测系统,这个系统的目的是什么,用户是如何使用系统的,用户对哪些业务的性能比较敏感,系统的一些关键业务实现逻辑是怎么样的,从设计实现的角度来看哪些业务的性能可能存在隐患。这些很少是技术层面上的问题,需要做的只是思考,再深入思考。慢慢的我有了些收获,开始了解为什么要测这个系统,针对这个特定的系统哪些内容是最重要的,为了获得需要的信息我需要从哪几个方面进行测试,为了实现我的想法又需要哪几种方法或者工具。(现在我的性能测试过程中,用于理解被测系统、理解用户、整理测试思路的时间投入大大增加了。你呢,投入了多大比例?)

  要做好这些其实很难,每一个被测系统对我来说,仿佛就变成了一个新的挑战。但是逐渐的我发现自己思考问题更全面了、可以更快的抓住系统的重点、找到更重要的BUG、对系统的实际性能有了更准确的评估。这里提一个简单的问题,如何确保你的测试结果和生产环境的性能表现是一致的,也就是说测试结果能够真正的反应实际的性能,而不仅仅是代表了你选取的几个测试场景的性能。话说起来比较绕,但是请认真想一想,你有多大的把握呢?

  上面只是写了一些个人的感想,我觉得如果在“思想”上没有办法上到一个新的台阶,你的性能测试生涯可能也就达到“瓶颈”了。如何突破这个瓶颈,那就需要努力改变自身,多思考多学习,最核心的能力恐怕不是能培训出来的。一定会有一些人认为性能测试的重点在于“技术”上,于是他们不断的记住各种调优配置参数,以为自己掌握了性能的精髓,仿佛什么系统到了他们手上,只要改几个参数就会出现奇迹。我也经历了这个阶段,也有过几次自以为挺高明的调优经历,也为自己会各种中间件数据库的配置调优而有些小得意。但现在想想,那还真是一个比较低的层次,思想上抓不住重点、看不全大局,技术上其实也只是一点皮毛。面对这类人,只要问几个为什么就会让他们无法回答,为什么要调优?为什么要调这个参数?如何证明这次调整的效果?

  将上文简单的总结成几点,希望能给性能测试新手提供一丁点的帮助吧:

性能测试的难点在于对被测系统的理解,在于对测试点的分析。为了实现测试的思想,可以有多种方法,手段永远只是辅助的,只有思想才是根本的。工具(如LR)更不等于性能测试,不要以为会用LR就懂了性能测试,那只是最低级的测试执行。也不要以为会调几个参数就懂了性能测试,那同样是个比较低的层次。

调优等技术不是性能测试的主要目的,好的性能也不是调出来的。测试人员一定要明白自己存在的价值所在,所谓的“技术”只是为了达成自己测试目的的一些手段,同开发人员、DBA相比,你在这些技术上永远是外行。

不要照着文档模板,填入测试方案。每一个系统都是不同的,要真正的认识到这一点,为每个系统设计出有针对性的测试方案。思考你每一步工作的意义和目的。

如何证明测试结果的有效性,其实是个很难的问题,值得花费时间去认真思考。这个过程涉及到一些很重要的内容,如用户模型的建立,后续会有专门的文章。

性能测试是一个需要不断改进的过程,每一次只需尽量的做到更好,多做一点点以前没有想到的东西。经过不断的积累,你会发现自己对性能测试有了更深的认识。

2、为什么我模拟的百万测试数据是无效的


测试环境的重要性无需多说,大家都知道测试环境要尽量的模拟生产环境,当然也包括数据。这样测试的结果才会更加准确的反应真实的性能。就连开发过程,都已经开始在大数据量下加压开发了。那么,关于测试数据,你了解多少呢?

  通常说的测试数据可以分为两类:

  一是为了测试性能而准备的数据,这是用来模拟“压力”的数据。也就是常说的数据量、历史数据等。一般都会根据需求或者经验很容易估算出来,比如案件年增长量为5%,去年数据量为100W,测试需要保证3年后系统仍可正常运行,那么就需要计算并模拟出3年后的总数据量,在这个基础上进行测试。

  二是用来辅助测试使用的数据。比如有一个对案件进行打分的功能,只有符合一定条件的案件才会出现在打分列表中。那么我们要测这个打分的操作,首先就要保证有可用的案件,这就需要去生成测试数据,该数据可能一经使用就失效了(已经打过分就不能再打了)。这样,每次测试这个功能,就需要准备这样一批数据。这里的测试数据,更多的是和测试流程有关,是为了能够正常的进行测试,而不是涉及到性能的。

  我们这里要说的是第一类,对性能测试结果产生直接影响的数据。

  先看两个小案例,涉及到了案件表(T_AJ)和法院编号列(N_FY)、立案日期列(D_LARQ)。案件表中模拟了一百万测试数据,测试简单的查询操作,根据经验,预期响应时间在2秒之内。

  案例1. 查询本院案件列表,相应的SQL如下:

select * from T_AJ
where N_FY=10
order by D_LARQ desc


  执行这个操作耗时近10s,显然达不到正常预期。
  经排查,生成的100W测试数据中,所有的N_FY列值都为10。这样,最明显的问题就是,查询的结果集数量完全偏离了正常范围。如果实际有100家法院,正常分布下,每家法院只有1W的案件,但测试数据的FY只有一个值,通过这个查询,查出了原来100家法院的数据。无论是在数据库处理中(如本例的排序),还是在程序的处理中(如展现或者是对数据做进一步处理),两者的性能差异都是很显著的。所以这个测试结果是无效的。

  有人说,这个例子太弱了,结果集差了100倍,性能当然不一样了。那是不是数据总量和结果集大小都一致,测试结果就是有效了呢?

  案例2. 查询本院一个月内收的案件,相应SQL如下:

select * from T_AJ
where N_FY=10 and D_LARQ between '20110101' and '20110201'


  这个操作,查出来的结果只有一千条数据,属于正常范围。但查询的时间还是超过5秒,依然超出了我们的预期。

  查看数据发现,N_FY=10的数据有近50万,占了总数据量的一半,D_LARQ在一月份的数据也占了差不多一半。但是同时符合两个条件的数据还是一千条左右。那么这里的问题就不在于结果集了,而是是否能利用索引进行查询,看如下两个图就能很好理解了。
  在正常数据中,每家法院的数据可能占总数据量的1%,一个月时间段内的数据可能占总数据量更少,假设是0.5%。那么这时我们通过N_FY和D_LARQ两个条件进行查询,数据库会进行估算:符合D_LARQ查询条件的数据大概有5000条,符合N_FY查询条件的数据大概有1万条,那么用D_LARQ上的索引进行查询是最快的,可以迅速的将查询范围缩小到5000条,然后在这5000条中去检查N_FY是否也符合条件。

  过程如图一所示(手绘草图^_^)。

  


图一

  注:数据按行存储,小方块表示符合该列查询条件的数据,阴影表示符合所有查询条件,也就是最终的结果集。箭头线段表示为了完成查询,需要扫描的数据量,本图中即符合LARQ查询条件的数据。下同。

  但在本例中不正常的数据条件下,数据库会知道:符合N_FY查询条件的数据有50万条,符合D_LARQ的也有近50万条,如果使用其中一列的索引将一百万的范围缩减到50万,比从头到尾扫描整个表做的工作还要多(为什么呢?需要了解索引的结构和原理),那还是不要用索引了吧。于是数据库会依次检查每一条数据,判断N_FY和D_LARQ是否符合条件。

  如图二所示。



图二

注:本图中实际扫描的数据量就是整张表的数据,但结果集和图一是一样大的。

  这样,就可以知道,总数据量一样,结果集大小一样,为什么性能差了很多了。就是因为数据分布不合理,导致数据库无法正常使用索引,从而进行了全表扫描。当然,这个数据分布,我们依然可以归类到结果集中去,那就是要保证每一个查询条件“单独的结果集”都要符合真实情况,而不仅仅是整个查询最终的“总结果集”。

  看个这两个简单的小例子,我们再来总结一下关于测试数据,需要注意的内容:

最根本、也是大家都知道的就是数据量,性能测试必须保证能在预期的数据量下进行测试。在一万条记录中查询,和在一百万数据中查询,显然是大大不同的,可以把数据量看做一种“压力”,这个就不用再解释了。

但是在比较大型的系统中,这一点可能也不是很容易做好,因为这类系统往往有着复杂的数据库,上百张的数据表。对每张表都进行数据模拟显然是不现实的,也是没有意义的,因为不是每张表都涉及到大数据量。那么如何选取不容易遗漏呢?通常通过两种方式:从设计和业务角度分析表间关系、从现有实际数据量进行分析推测。

确保结果集在正常范围内。结果集的大小直接影响后续很多工作的性能,如数据排序分组、分页、程序中的逻辑校验或者是展现。

数据分布必须合理,尽量接近真实。数据的分布,其实也就是数据的真实性,它直接决定了数据库是否使用索引、选用哪个索引,也就是常说的查询计划。不同的查询计划也就是不同的数据访问路径,性能差别可能会很大。

这里主要涉及到的是索引的问题,需要大家对索引的原理有一定的了解,索引如何工作、数据库如何选择索引、和索引有关的一写重要概念如区分度(selectivity)等等。

最好的数据来自生产环境。这是显而易见的,使用真实的数据测出来的结果才是最准确的。但是绝大多数情况下,我们没有这样的好运,可能是客户禁止、也可能是生产环境数据量比较小。那就只好自己想办法来模拟了,需要注意的也就是上面说到的几点。这里再推荐一种方法,数据翻倍。比如已经有了真实的数据十万条,但我们需要一百万条,那就可以通过写一些SQL或者存储过程,将现有的数据不断翻倍(简单的说,复制到临时表,根据需要修改一些列,再插回到原表),这样的数据真实性还是比较高的。

  关于测试数据,我想说的就是以上几点了。另外再补充上一些相关内容,也是性能测试人员需要关注的。

重点了解IO的概念,更准确的说应该是物理IO。一般来讲,数据库的瓶颈或者查询的主要耗时就是IO。所以,数据库优化的一个重要方向就是尽量减小IO。

IO是不是只和数据量(行数)有关呢?举一个例子:

select co1, col2, col3, col4, col5 from T_AJ
where condition...


T_AJ数据量有100万,表中有近200列,此查询耗时大于10秒。而另一种实现方式,首先将col1-col5以及查询条件中的几个列的数据抽取到一张临时表(#T_AJ)中。然后,

select co1, col2, col3, col4, col5
from #T_AJ where condition...


临时表#T_AJ和原数据表有同样的数据量(行数),但是此查询却只需要1秒(暂不考虑抽取到临时表的耗时),这就是不同IO引起的差异。通常我们使用的数据库都是行式存储的,可以简单的理解为,一行数据从头读到尾,才能进入到下一行。这样,不管一行中的200列,你只读取其中的一列还是几列,其余的190多列仍然需要一定的IO。在大数据量下,这个性能差异就很明显了。所以上面的这个例子就是一种典型的优化手段,索引覆盖也是处理类似问题的典型方法,各位自行了解吧。列式存储数据库(如Sybase IQ)之所以性能这么高,也是同样的道理。

尽量深入了解这些概念,如执行计划,基于开销的估算,统计信息等等。我用一句话来简单描述:数据库通过统计信息来估计查询开销,统计信息不准时,开销估计就可能不准确,从而导致选择了错误的执行计划。

测试过程中数据的清理。性能测试过程中可能又会生成大量的数据,积累到一定程度又会对性能结果造成影响,所以每一轮测试时都应该清理掉之前测试过程中产生的数据,保证每次测试是在相同的条件下进行的。

性能测试过程中,如果定位到了某一个查询或SQL有问题,首先要确认的是数据是否合理。通过查询计划来判断是否按预期进行了查询,如果不是,查看数据的分布是否真实。一般数据库会提供很多种手段来进行验证。

  最后,本文所写内容都是针对传统的行式存储数据库的,还请大家注意。

3、用户数和压力

同样的项目、同样的性能需求,让不同的测试人员来测,会是相同的结果么?

  假设有这样一个小论坛,性能测试人员得到的需求是“支持并发50人,响应时间要在3秒以内”,性能测试人员A和B同时开始进行性能测试(各做各的)。

  只考虑发帖这个操作,A设计的测试场景是50人并发发帖,得到的测试结果是平均完成时间是5秒。于是他提出了这个问题,认为系统没有达到性能期望,需要开发人员进行优化。

  B设计的测试场景是,50个人在线,并且在5分钟内每人发一个帖子,也就是1分钟内有10个人发帖子,最后得到的测试结果是平均完成时间2秒。于是他的结论是系统通过性能测试,可以满足上线的压力。

  两个人得到了不同的测试结果,完全相反的测试结论,谁做错了?

  或许这个例子太极端,绝对并发和平均分布的访问压力当然是截然不同的,那我们再来看个更真实的例子。

  还是一个小论坛,需求是“100人在线时,页面响应时间要小于3秒”。A和B又同时开工了,这时他们都成长了,经验更加丰富了,也知道了要设计出更符合实际的测试场景。假设他们都确认了用户的操作流程为“登录-进入子论坛-(浏览列表-浏览帖子)×10-发帖”,即每个用户看10个帖子、发一个帖子。于是他们都录制出了同样的测试脚本。

  A认为,每个用户的操作,一般间隔30s比较合适,于是他在脚本中的每两个事务之间加上了30秒的等待(思考时间)。

  B想了想自己看论坛时的情景,好像平均每次鼠标点击要间隔1分钟,于是他在脚本中的每两个事务之间加上了1分钟的等待。

  他们都认为自己的测试场景比较接近实际情况,可惜测试结果又是不同的,很显然A场景的压力是B的两倍。那谁错了呢?或者有人说是需求不明确导致的,那么你需要什么样的需求呢?

  看看我随手在网上(51testing)找的提问吧,和上面的内容如出一辙。一定有很多的性能测试人员每天接到的就是这种需求,又这样就开展了测试,结果可想而知。

4、一切来自于录制

经常会有性能测试新手问这样的问题:
  C/S的系统如何录制,应该选择什么协议呢?
  待测系统A的一个功能,是由B系统调用的,也需要搭建B系统的测试环境并对其录制么?

  我的回答是,先弄清楚你想测的是什么?对它而言,压力又是什么?
  新手总是想着如何录制客户端的操作,如何模拟客户端的点击。这种想法应该是受到了主流测试工具影响,性能测试的入门基本都是从工具开始,比如使用最广的LR,其最方便好用的功能应该就是录制了。但是需要清楚的是,录制只是为性能测试提供便利的一个功能(可以傻瓜式的产生向服务器施加压力的脚本),录制本身并不是性能测试的根本或者所必需,能够产生压力的那些脚本或是程序才是关键所在。

  第一个问题,比如一个即时通讯类的软件如何测试?
  首先要明确你想测的是客户端还是服务端,如果是服务端,那么服务端承受的压力是什么呢?
  是每一条消息都要经过服务器么?
  服务器是要将消息进行存储,还是仅仅转发?
  不同的功能,如普通会话和多人会话,从服务端来看的区别是什么?
  客户端是如何同服务端通信的,是采用了一些标准的开源协议(如XMPP),还是经过了自己的重新扩展?
  ……

  为了回答那两个看似很简单的问题(想测什么?压力是什么?),其实你需要了解整个系统的运行方式。这些信息完全可以从一些设计文档或者开发人员的口中获取到,并不需要你能读懂源码。
  如果我知道了这个软件使用了XMPP协议,一条普通的会话是客户端向服务器发送了这样一条信息:

?
  而多人会话是客户端发送了这样的信息:

?
  那么应该会知道,表面上这些不同的功能,其实只是客户端发送信息中个别字段的区别而已。那么我就可以想办法直接向服务器发送这些信息,让服务器根据接收信息的内容去完成相应的功能。也许根本没有必要去想如何录制客户端发起一个会话并发送消息这个动作,或者发送文件、群消息等等其他操作。
  至于如何实现,如果你有编码能力,可以将开源代码引入到自己的测试代码中(需是标准协议),否者可能需要让程序的开发人员实现一个测试程序。不要不敢开口,开发人员协助进行性能测试是很正常的,而且这种工作量不会很大,只是把程序中的一些代码封装成一个可配置可方便调用的执行文件。
  让开发人员来实现测试工具不丢脸,怕的是你自己不知道测试工具应该实现成什么样。(当然,如果自己可以看源码来实现工具那就更好了)

  第二个问题,同样的,所谓的B系统调用A系统这个动作,是如何实现的?
  会不会只是一个简单的HTTP请求?
  或者是调用A系统的一个webservice接口?
  你要测的是A的这个功能么?

  如果是,那我们为什么一定要通过B系统来录制这A的这个功能呢?完全可以直接向A发送请求或者是调用接口(如LR中的webservice协议)。
  至于具体如何做,可能有很多现成的接口测试工具,也可能仍然需要开发人员的协助。比如B与A之间传递的数据是经过加密的,那对(黑盒)测试来说就会非常困难,这种情况下,确实有可能通过B来录制会更简单。

  在51testing上看到的一个问题,问如何测试一个统计报表的另存为(excel)功能。
  
点这个按钮后,服务器会生成一张报表,然后弹出浏览器的另存为对话框,保存为本地文件。提问题的这个人遇到的困难是,LR中好像没法录制“另存为”这个动作。
  之所以会有这样的问题,根本原因还是没有理解系统的运行原理,没有区分哪是服务器、哪是客户端。

  一般来说,这个过程是这样的:

  点另存为按钮时,向服务器发送了一个计算报表的请求,这个请求中会包含一些参数,如报表类型、统计时间等等。

  服务器计算完成后,将结果数据返回给客户端(浏览器)。

  浏览器本身的功能,将数据保存为一个本地文件。

  (这里假设了计算过程是另存为按钮触发的,如果是打开页面时就计算完,那点按钮时甚至有可能根本没与服务器进行交互)

  如果明白了这个过程,那么就不会纠结于录制“另存为”这种事情了,你要做的只是向服务器发送一个请求,然后接收响应数据。
  那么就不需要生成本地文件了么?当然不是,否则怎么验证返回的数据没有问题呢。只不过这个文件的操作需要自己来实现了,创建文件、写入数据、关闭文件。

  最后再总结一下要点:

  理解系统的运行原理

  区分服务端和客户端

  弄清楚你要测的是什么,哪些东西其实是可有可无的

  要模拟的是服务器的压力,而不是客户端的操作

  录制只是一种手段,很多情况下并不是最佳选择

  开发人员的协助是应当的,但前提是你要明确的知道应该如何测试

5、这是性能问题吗

经常会见到新人提出这样的性能问题:
“100用户时,A操作响应时间达到了XX秒,请修改”
“场景运行2个小时后,系统没有响应了”

面对这样的问题,开发人员一定会觉得很无助,他们甚至不知道问题是什么。
即使从测试人员的角度来看,这也算不上是一个合格的问题。甚至是不是真正的问题,都要暂时打上问号。
那么一个合格的性能问题应该是什么样呢?

首先要证明这是一个问题

开发人员面对测试提出的问题时,第一反应很容易是“我的程序没有问题,是你的使用不正确”,想必大多数测试人员都有过这种感受吧。手工功能测试尚是如此,更不用说性能测试了,因为性能测试的核心在于“模拟”二字,模拟大量用户、模拟大数据量……这必然要引入很多测试工具、测试代码。那么工具使用的是否正确、代码编写是否可靠、模拟的用户和数据是否真实,都可能直接影响到测试结果。由于测试而引入的问题,有经验的性能测试人员一定有所经历,一些可能会留下很深的印象。因为这种问题的后果往好了说是耗时耗力、最后证明测试不当,往坏了说可能会误认为系统存在问题、做出了不该有的改变。

那么如何才能证明测试过程没有问题,有问题的是被测系统呢?简单的说,是要把测试过程公开化,把测试的方法、测试的具体场景、测试代码的实现、测试环境等等拿出来让开发人员、业务人员等评审和确认,让相关人理解具体的测试过程,让大家知道你到底在做什么。这是一个说起来容易,实际中很难做好的工作,只有靠制订测试过程的详细规范才能从源头去主动的改善这一过程。否则,靠你的嘴皮子去和开发人员理论吧。

好问题要描述清晰

100个用户,是指绝对并发操作么?还是什么样的场景?
是只测这一个A操作?还是有多个操作在同时进行?
如果有多个操作,是只有这一个操作变慢?还是普遍变慢?
测试环境是什么样的?测试数据量是多少?
这又回到了上面那个“测试过程公开化”的范畴了。也许开发人员理解了详细的测试场景后,会告诉你,这个场景在业务中是不可能的,或者测试数据量是不合理的。

好问题要有尽量深入的定位

只是描述清晰还不够,要明白什么是表面现象,什么才是问题。
问题是需要定位才能发现的。
“100个用户操作时,A事务的响应时间过长”,这只是一个场景的运行结果,只是一个现象,问题是什么呢?
响应慢是慢在哪?是中间件还是数据库?这是最基本的分层定位。
是服务器达到了硬件瓶颈么?如果硬件或操作系统上没有瓶颈,那么瓶颈在哪?
是不是由于一些基本配置问题导致了排队呢?比如中间件的HTTP线程数和数据库的连接数。
如果基本配置没有问题,那么再深入一些,是内部的哪些资源产生了争用和等待么?
是哪些SQL引起了数据库内部资源的争用呢?应用程序上又是哪个方法在占用资源呢?
……
定位的越深入,需要的技术能力也就越高。

好问题应该用最简单的手段复现

比如上面的100个用户,导致了数据库的一张表的争用,因此产生了大量锁等待现象,最终导致了外部的A响应时间过长。但是通过之前的分析和定位,我们发现也许引发问题的那些SQL语句,只来自100用户中的10个特殊类型的用户。那么这个问题就完全可以简化成用10个用户去复现,其他90个用户都是干扰。这样问题被简化了,开发人员也就更容易理解问题,对于测试的复测也更加方便。
不过还是要记住,最终的用户场景模拟才是决定性的验证。

最后再总结一下,性能问题到底应该如何提呢?其实只有一个标准,那就是能让开发理解问题、找到根本原因并进行修正的就够了(假设开发人员无所不能)。再进一步深入的分析,可能是为了减轻开发的一些负担,也可能是为了锻炼自己的能力,这就不是每个测试人员都会去做的了。

[b]6、性能监控 [/b]

“数据库(或中间件)非常慢了,如何监控它的性能”
“你想得到什么性能指标?”
“就是……内部的性能指标”

收到性能测试人员这样的问题后,通常会发生上面的对话。
我的观点是,准确的说出你想要做什么,比你会不会做更重要。
那么对于性能测试人员来说,”性能监控“这门必修课,该从何下手呢?

监控什么

如果我给你一个黑盒子,告诉你里面是一部机器,要监控它的性能。你能做到么?当然不能。因为你不知道这部机器如何运行,你不知道对它而言性能是什么。

性能测试也一样,说到操作系统,大家都知道性能指标要看CPU、MEMORY、DISK IO以及NETWORK等等。但是到了数据库和中间件,如果测试人员说不出具体内容,这表明他不知道针对这个对象,性能是什么,即便把最完整的性能指标摆在面前,恐怕也是没有意义的。

当然知识和经验是一步步积累起来的,但也需要测试人员去主动的学习。从系统体系结构、运行原理到性能监控、性能调优基础和方法,官方手册总是最好的教材。

那么在没有掌握这些知识之前,我希望上面的问题是这样问,“数据库(或中间件)非常慢了,一般需要监控它的哪些性能指标呢”,得到回答后赶紧翻资料吸收相关的知识。

过程中的监控

性能测试新手容易忽略测试过程中的性能监控,而只给出一个最终的测试运行结果。
比如这个问题,“测试运行3小时后,系统没有响应,中间件无法连接”。

对于这样的问题,期望开发人员如何处理呢?中间件已经无法连接,想获取到一些内部的性能指标恐怕都已做不到。只有重运行一次,让开发人员来关注过程中的运行状况,但这本应是由测试人员来做的。

如果我们知道,中间件本身无法响应一般可能是因为这两个问题:
JVM堆内存用满,不停的进行GC,导致响应超慢(但是还没有OOM,否则就报错了)
处理HTTP请求的线程,都被占用或者锁住

那么我们就可以在测试过程中去监控这两项数据,跟踪变化趋势,直到系统再次无法响应。如果正好其中的一个资源也耗尽了,那么就可以确认“无法响应“这个现象的直接原因。实际上,这两个指标基本也是中间件最重要的指标,理应每次测试过程都进行监控和数据采集了。

监控的层次

系统的性能表现会涉及到多个层面,比如:
中间件 -> 中间件操作系统 -> 数据库 -> 数据库操作系统 -> 客户端

监控时也要着眼于多个层面,这样才有可能更接近问题的本质。还是上面那个中间件无法响应的问题,假设我们观察到了所有HTTP线程都被占用,也许更进一步我们又会发现这些线程都在执行数据库的查询,而这些查询在数据库中的状态依然是running,那就说明更根本的原因是在数据库层面。这也就是问题的逐步定位。

全面的监控

片面的数据不足以说明问题,系统的方方面面常常是相互影响的。
比如数据库的CPU占用很高,并不能证明系统是计算密集型、CPU是瓶颈,也有可能是spinlock的争用导致了CPU骤增。
再比如大量的page-in IO可能会使内存出现瓶颈。

上面的层次问题其实也属于”全面“的范围。只有拿到全面的数据,才有可能分析出正确的结论。
当然,这又是一个需要积累的过程,如果连spinlock都不知道,又怎么可能有准确的判断呢。
方法还是一个,主动的学习,系统的学习。

7、你需要调优么

测试人员喜欢在得到某个达不到预期的性能结果后,进行一下“调优”。
PM有时也会布置任务,测试完成后“调一个优”。
一些人貌似有了这种观念:调优才使性能测试有意义、性能测试的目的就是调优、做调优才能显出测试人员的水平……

随着经验的增长和对性能更深入的认识,我越来越体会到调优是一个复杂的过程,不是动动嘴、改俩个参数这么简单,只有通过科学的方法和扎实的技能才能做好,以至于我使用这个词的频率越来越低,因为不敢轻易说出口……

在你再一次调优之前,先考虑以下几个问题:

为什么需要调优

如果问起这个问题,得到的回答通常是“因为性能不够好”,那么接下来我会问性能不好体现在哪里?你要调什么?希望得到什么结果?
如果你不能足够准确的回答第一个“体现在哪里”的问题,后两个也一定没有答案,所谓的调优自然也无从谈起。而这第一个问题的答案其实也就是定位的过程。

举一个小例子。如果我已经发现数据库较慢,通过进一步监控又发现了一个cache的spinlock contention这个指标超过了正常的范围。那么我会猜测可能是这块缓存的争用导致了数据库的运行状况变差,针对这个现象我知道可以通过将cache分区来减少争用,改变配置后再重新测试和监控,这就可以算是一次调优的尝试。

但如果你只停留在数据库慢的这个层面上,又怎么能进行调优呢?
所以,需要调优的一个前提是“定位到问题”或者“发现了瓶颈”。

又有人说了,没有问题为什么不能调优?没有问题,我们可以让系统变得更好!
但是,所谓的“更好”如何衡量?“好”到什么程度时不需要继续“好”了呢?
请记住,瓶颈永远存在,消灭了一个,就必然会引入另一个。
调优的目标也不是“没有瓶颈”,而是系统在其所承受的压力下,性能表现足够好,那就够了!
“足够好”其实也就是没有问题。

调优调什么

理解了上面的内容,这个问题的答案就很明显,调优必然是针对具体的问题或瓶颈。
而问题和瓶颈,指的是“性能不好”这个现象的直接原因,而不是那些不痛不痒的其他因素。

好比奥拓比奥迪跑得慢,最主要的问题在于发动机(不懂车,随便一说),而不是奥拓车的外型不够流线、轮胎抓地不够好……
如果把精力放在改善外型、轮胎这些方面上,确实会让奥拓变得更"快",但是从原问题(比奥迪慢)上来看,这都是没有意义的。

至于如何准确的定位出问题,针对问题又如何下手,这就是技术能力,只能依靠不断的学习、长期的积累了。
不过依然存在一些比较科学的工作方法,可以让你尽快的抓住重点。如在系统运行正常时采集一份足够完整的性能指标作为基准,当出现状况时再次采集一份相同的指标,对比其中的差异,从差异处入手。

经常见到这种人,一听到数据库慢,直接加大内存分配、加缓存、加连接数、加大各种资源配置……典型的胡乱“调优”。

调优的层次

同一个问题,可能可以从多个方面进行处理。
一个慢SQL,优化的方式可能是加个索引、绑定缓存、改写SQL、表分区、甚至是升级硬件。
资源争用问题,既可以从配置层面进行优化、减小争用发生的机率,又可以从程序的实现方式上做改变、从源头上避免争用。

假设多种处理方式,都可以满足期望,那么应该从哪个层面下手呢?
这就需要考虑到工作量、效果、隐患等多种因素,当然也不排除几种优化共同作用。

调优有效么

这是一个工作方法是否科学的问题。
每一次试验,都需要能够验证是否有效。有效的保留,无效的则复原。
除了对原问题的验证,还必须确认对其他部分是否产生了副作用。理论上这就需要在每一次调优尝试后,进行一次足够全面的复测。
否则,很容易出现“拆东墙补西墙”的问题。

记住以下几个要点:

每次只改变一处。

每次改变后进行复测。有效的保留,无效的复原。

不断的迭代,直到达到预期。

只有真正理解调优的目的,并按照科学的方法行动,你的努力才会体现出价值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: