1. 测试真实的应用程序
1.1. 应该以实际产品的使用方式进行测试
1.2. 所有的基准测试通常都包括一个预热期,在这期间,JVM可以将代码编译到最佳状态
1.3. 微基准测试(microbenchmark)
1.3.1. 通过测量一小部分代码的性能来确定多种实现中哪个最好
-
1.3.2. 必须读取测试的结果
1.3.2.1. 从局部变量改为实例变量(用volatile关键字进行声明)即可测量这个方法的性能
1.3.2.2. 即使微基准测试是单线程的,也需要使用volatile变量
-
1.3.3. 必须测试一系列的输入值
- 1.3.3.1. 最好提前算好输入值
-
1.3.4. 必须测量正确的输入值
- 1.3.4.1. 捕获异常
-
1.3.5. 代码在生产环境中可能有不同表现
1.3.5.1. 对于不那么频繁的操作,修复微基准测试发现的纳秒级别的回归问题就会浪费时间,将这些时间用于优化其他操作必然更有益
1.3.5.2. 若一个集合被访问上百万次,那么每次访问节省的几纳秒就很重要
-
1.3.6. 必须包含一个预热期,让编译器有机会生成最佳代码
1.3.6.1. 必须有预热期,否则它测量的就是编译性能,而不是代码性能
1.3.6.2. Java的一个性能特点是,代码执行得越多,性能就越好
1.4. 宏基准测试(macrobenchmark)
1.4.1. 要测量一个应用程序的性能,最好的测量对象就是应用程序本身,外加它使用的任何外部资源
1.4.2. 资源分配
1.4.3. 在没测试整个应用程序的时候,不可能知道优化哪部分的性能会有效果
1.5. 介基准测试(mesobenchmark)
1.5.1. 介于微基准测试和宏基准测试之间
1.5.2. 比微基准测试的缺陷更少,也比宏基准测试更容易操作
1.5.3. 更容易使用多线程
1.5.4. 比完整的应用程序更有可能遇到同步瓶颈
1.5.5. 介基准测试的性能特点比微基准测试的更接近实际应用程序
1.5.6. 用介基准测试进行自动化测试也是很好的方法,特别是在模块级别的测试中
2. 理解吞吐量、批处理和响应时间
2.1. 测量批处理时间
2.2. 测量吞吐量
2.2.1. 基于一定时间内可以完成的工作量
2.2.2. 每秒事务数(TPS)
2.2.3. 每秒请求数(RPS)
2.2.4. 每秒操作数(OPS)
2.2.5. 吞吐量测试几乎都是在适当的预热期之后进行的
2.3. 响应时间
2.3.1. 从客户端发送请求到收到响应之间的时间
2.3.2. 在响应时间测试中,客户端线程会在操作之间有一段休眠时间,这被称为思考时间
2.3.3. 周期时间(并不是思考时间)
-
2.3.4. 平均响应时间
- 2.3.4.1. 将单个时间加在一起,再除以请求数
-
2.3.5. 百分位响应时间
- 2.3.5.1. 举例,如果90%的响应小于1.5秒,10%的响应大于1.5秒,那么1.5秒就是第90百分位响应时间
-
2.3.6. 平均响应时间和百分位响应时间的区别
2.3.6.1. 异常值会影响平均值计算。
2.3.6.2. 因为在计算平均值时会用到异常值,异常值越大,它对平均响应时间的影响就越大
-
2.3.7. 优化重点应该是降低异常值的影响(从而缩短平均响应时间)
2.3.7.1. GC引入的暂停时间会让Java程序更容易出现异常值
2.3.7.2. 通常关注第90百分位响应时间(或者第95百分位响应时间和第99百分位响应时间
2.3.7.3. 如果你只能测量一个数字,那么最好选择基于百分位响应时间的测试,因为减小这个数字将惠及大多数用户
2.3.7.4. 最好同时测量平均响应时间和至少一个百分位响应时间,这样你就不会错过异常值过大的情况了
-
2.3.8. 负载生成器
2.3.8.1. Faban就是基于Java的开源负载生成器
2.3.8.2. Apache JMeter
2.3.8.3. Gatling
2.3.8.4. Micro Focus LoadRunner