是的,我在 这 里想 说 的就是 这 句名言, Devils are in the details.
事情的来源是 这样 的, 节 前和几个同事在公司内部开了一 门 叫 advanced performance testing 的多次 课 程,某次 课 后,我布置了一个 homework 。主要目的是 练习 性能 测试 中的几个概念,比如 think time , assertion 等。
考 虑 到是第一个 homework , 题 目本身比 较简单 。
Task: Test the performance of our web proxy.
Suppose there are 2 groups of users.
1. Tech guys (40%)
http://www.sina.com.cn/ --> http://tech.sina.com.cn/ --> http://tech.sina.com.cn/internet/
2. News guys (60%)
http://www.sina.com.cn/ --> http://news.sina.com.cn/ --> http://news.sina.com.cn/world/
Should include:
Think time, web page result check.
-------------------------------------------------------------------------------
为 了避免把 事情弄复杂,没有涉及到 POST和变量的操作,要求大家用 JMeter来完成,提交 jmx脚本和结果的截图,以及简单的说明。
其 实 布置 这 个作 业 的 时候,我还比较担心是不是太简单了,起不到锻炼的作用。不过这两天在家把十几份作业全部 run了一遍之后发现其实有很多值得探讨的地方,而且有些点自己之前也没有搞明白,虽然这个工具也用了好久。
下面我们来详细的说说细节的事儿。
1. response time
这是一个看起来很简单但是实际比较复杂的指标,幸好这里还不涉及 time to first byte 之类的概念,也且先不管不同的分析方法,但是也发现有几类不同的统计方式。
a. 把上面每一个 http request 的时间统一来看,看到的是每一个 request 的响应时间。
b. 按不同的请求类型来看,例如 homepage, tech, internet, news, world , 然后看每类请求的响应时间。
c. 把每类用户的系列操作当成一个 transaction 来看,然后看整个transaction的响应时间。
在不结合需求的情况下,这些没有对错,关键看哪种是你想要的。
2. Assertion
Assertion 在性能测试中,特别是 WEB的性能测试中是很重要的校验手段。在看大家提交的脚本中发现有几种做法。
a. 检查response的body中是否有“新浪首页”字样,这也是最多的一种做法。这种做法很直接,但是可能会稍显单薄,因为动不动几百KB 的 body,别的页面也可能有这样的字眼。当然我们也可以加多个这样的关键字。
b. 检查HTML 格式的内容,比如“ <title>新浪首页</title>”,这种可能比纯粹检查关键字要好一点。
c. 检查response header 。比如 check host是 sina.com.cn, 并且 HTTP code是 200。这个方法看起来不错,但是可能会有一个很大的问题就是,现在很多网站的错误页面也看起来像是一个正常的页面,而且返回码都看起来是正常的。这也是设置 assertion所想要避免的一个问题。因为工具本身就可以自动的根据 code来判断成功还是失败。
3. Recording
录制是创建脚本的一种常用的方法, JMeter提供基于 proxy的录制的功能,当然也可以借助于 badbody之类的工具来完成。于是我们也可以借助录制来获得上面题目需要的脚本,也确实有人这么做。
看到上面的脚本,虽然运行起来可以 work,会发现有些问题,首先是太过与复杂,难以维护,其次是依赖性太强,因为很多是具体的元素的 URL,比如某个图片,某个广告动画,这些东西是变动很快的,那么下次脚本就可能会实效。
4. Think time
这是一个性能测试中比较基本的概念,结合到 JMeter中,发现大家用了两种不的方法来实现。一种适用 test action中的 thread pause,另一种适用 constant timer。问题是两种效果是一样的吗?都能达到我们想要的目的吗?
我也拿不准,所以做了个实验。
关于 Thread pause:
涉及一个 test plan, 流程是这样的: GET google.cn --> thread pause 5s --> GET google.cn --> thread pause 5s
Test with thread pause
得到的结果是。
结合数据里面的时间戳,发现基本是安装我们设想的那样来运作,每完成一次请求之后 sleep 5s。
关于 Constant timer :
设计的流程是: GET google.cn --> Constant timer 5s --> GET google.cn --> Constant timer 5s
得到的结果如下:
仔细看一下,和上面的解雇完全不同,每一个请求之间间隔了 10s,正好是两个 timer加起来的时间,所以这个 timer不是很多人设想的那样在每次请求之后 sleep 5s,而是这种看起来很奇怪的行为。我试验了好几次,包括把 timer放在 thread group的不同的位置。
我想可能不少人对于这个结果都比较 surprise,如果是这样的话测试出来的结果就会差很多,这也是在做 virtual user creation很担心发生的问题,模拟出来的用户行为和我们想要的很不一样。
联想到上次文章中提到的性能测试要求宏观,也很强调微观,特别是一些 critical details。是的,魔鬼就藏在细节中,技术的精进也是在于细节中,共勉。