标签:
平台和约定
调优参数
性能
测试真正应用
第一个原则就是性能测试必须在即将上线的产品上进行测试。
Microbenchmarks
public voiddoTest(){
// Main Loop
double l;
long then= System.currentTimeMillis();
11
for(int i= 0; i< nLoops; i++) {
l=fibImpl1(50);
}
long now= System.currentTimeMillis();
System.out.println("Elapsedtime: " + (now- then));
}
...
privatedouble fibImpl1(int n) {
if(n< 0)throw new IllegalArgumentException("Must be > 0");
if(n== 0)return 0d;
if(n== 1)return 1d;
double d= fibImpl1(n-2) +fibImpl(n- 1);
if(Double.isInfinite(d))throw new ArithmeticException("Overflow");
return d;
}
上面的程序存在几个问题,第一,因为变量‘l‘没有使用,所以编译器会优化掉调用fibImpl1的所有代码,所以实际执行的就是打印时间的代码,根本测试不到fibImpl1的性能。第二,因为我们的目的是得到第50个Fibonacci的值,对于比较智能的编译器,可能会去除循环。第三,必须要对正确的输入进行测试,因为在实际运行的时候,输入一般都是正确的。
注意:Java代码有一个特征就是:执行的次数越多,它执行得越快(所谓:warm-up period)。所以在进行microbenchmark的时候需要包含warm-up period,以便给予编译器产生优化代码的机会。
Macrobenchmarks
用于测量一个应用的性能的best thing(最佳东西?)就是应用本身,并结合它使用任何外部资源。如果应用调用了LDAP的API来确认用户的身份,那么测试的时候就会考虑LDAP调用。撇开LDAP进行测试对于模块测试是有意义的,但是对于性能测试,必须要考虑到LDAP调用。
随着应用的增长,满足上面说的准则(使用应用本身并结合它使用的外部资源进行测试)会变得更加重要,但是也变得更加困难。复杂系统比组成它的各个部分之和更加复杂,当把各个部分组合在一起的时候,它们的行为会变得非常不一样。比如:如果我们mock了数据库,那就意味着我们不用关注数据库的性能了。但是,在真正运行的时候,数据库连接会消耗很多heap space来存放它们的缓存数据;网络会变得更加繁忙,因为传输数据会增加;代码的优化会变得非常不同(简单的代码和复杂的代码)。CPUpipeline和Cache在较短的代码路径上比在较长的代码路径上更高效等等。另外一些原因就是资源的分配。在理想环境下,对应用中的每一行代码都有足够的时间进行优化,但是在现实环境中,对优化消耗的时间是有要求的,并且只优化复杂环境下的一部分也许不会立马得到很好的效果。考虑下图中,用户发送数据到系统,首先确认用户权限,然后做一些业务相关的计算,然后从数据库中加载所需的数据,再做一些业务相关的计算,并把一些数据存入数据库,最后向用户发送响应。下图中的每个框都是一个小模块,框中小括号部分是该模块最大处理的并发数。
从业务的角度来看,业务相关的计算是最重要的,这也是整个系统的目的;但是在上面的例子中,将它们的处理速度提升1倍是没有意义的(因为LoadData的RPS只有100)。任何应用(包括:单机JVM)都可以模块化为上面这样的一个一个步骤,每个步骤都以一定的速率向下一个步骤传输数据。
小贴士:如果有多个JVM同时运行在同一台机器上,我们必须要将所有JVM作为整体同时进行测试;因为有可能出现这种情况,单个JVM运行得很好,但是当多个JVM同时运行的时候,一些应用的性能会非常不同,比如:一些应用在GC的时候会占用比较多的CPU,当它在独立运行的时候没有问题,但是如果有其它应用一起运行的时候,它就可能得不到充分的CPU,导致运行性能下降。这就是为什么我们要对应用进行整体测试的一个理由。
Mesobenchmarks
代码样例
注意到:curDate是按天进行增加的。
这个实现不是最高效的算法,但是这么做是故意的,它可以增加些业务计算的时间。
这个类可以注入不同的history bean的实现(提前计算或延迟计算);它还可以缓存数据(或不缓存),这个对于一个企业应用是很平常的事情。
理解吞吐量、处理时间(批量操作)和响应时间
处理时间(批量操作)
吞吐量
响应时间
小贴士:响应时间和吞吐量:使用包含think time的客户端来进行吞吐量测试有两种方式。最简单的方式是让客户端在请求之间睡眠一段时间:
在这种情况下,吞吐量在一定程度上依赖于响应时间。如果响应时间是1秒,那么客户端每31秒发送一个请求,因此吞吐量为0.032OPS;如果响应时间是2秒,那么客户端每32秒发送一个请求,吞吐量变为0.031OPS。
另外一种方式是使用cycle time(而不是think time)。Cycle time设置请求之间的总时间为30秒,因此客户端睡眠的时间依赖于响应时间。
这使得吞吐量固定为0.033OPS,而不管响应时间是多少(假定每个请求的响应时间都小于30秒)。在测试工具中think time常常是变化的,它们的平均时间大致是某个值,但是为了更好地模拟用户行为,每个请求的hink time是随机的。除了这个原因,线程调度也不可能是实时的,因此请求之间的真实时间都是有些不同的。因此,即使使用提供cycle time的工具,测试多次,每次测试的吞吐量也是会有所不同的。
下图中20个请求,它们的响应时间分布在不同的范围当中。其中下面的黑粗线是平均响应时间为2.35秒;第一个黑粗线是90%的请求响应时间,这个值是4秒。
而上图中,90%的请求响应时间为1秒,但是平均响应时间却为6秒,这就是极值对响应时间产生了巨大的影响。
上面的例子,使用25个客户端(-c)产生请求到stock servlet上面(SDO来指示);每个请求有1秒的Cycle time(-w 1000)。这个测试有300秒的warm-up period,然后是5分钟的测试,然后是1分钟的ramp-downperiod( -r 300/300/60)。
理解波动性
标签:
原文地址:http://blog.csdn.net/qq_28674045/article/details/51743922