1.1 性能问题的现状
传统软件开发流程
传统开发流程与添加了性能测试流程的开发过程的区别,建议做法:
- 性能测试是否通过设定为是否能够发布的一个标准
- 性能分析贯穿于分析(详细设计/erd设计)、设计、编码的流程中
- 在自动化构建和测试中添加必要的自动化性能测试,并将结果以邮件方式发送给干系人,对于不达标的测试,将不达标的测试和测试数据自动录入缺陷管理系统
- 将统计方法和自动统计分析添加到自动化性能测试系统(第8章详细讲解)
将性能测试加入到传统的软件开发流程中。应用的性能需求如何挖掘,下面以吞吐量和延迟性为需求需要考虑的问题:
- 应用预期的吞吐量是多少?
- 请求和响应之间的延迟预期是多少?
- 应用支持多少并发用户或并发任务?
- 当并发用户数或并发任务数量达到最大时,可接受的吞吐量和延迟是多少?
- 最差情况下延迟是多少?
- 要使垃圾收集引入的延迟在可容忍的范围内,垃圾收集的频率应该是多少?
需求文档中应能够对应以上问题,并以此制定基准测试和性能测试,确保应用能够满足性能和扩展性需求。
1.2 性能分析的两种方法:自顶向下和自底向上
1.2.1 自顶向下:着眼于软件栈顶层的应用代码的更改和使用,从上往下寻找优化的机会和问题
自顶向下的第一步总是对应用进行监控,监控的内容包括:操作系统、Jaa虚拟机、JavaEE容器以及应用的性能测量指标。
基于监控的结果再开展下一步操作,下一步操作例如:JVM垃圾收集器调优、JVM命令行选项调优、操作系统调优等
1.2.2 自底向上:从软件栈底层(如CPU指令效率、CPU高速缓存)开始,逐渐上升级到应用自身的结构或应用常见的使用方式。
自顶向下和自底向上可以用来查询和解决不同类型的性能问题。
自底向上的常见分析方法:
- 迁移应用到其他操作系统(不改变源代码)
- 将应用部署到不同的运行环境中
- 更改jvm版本,生成更有效的机器码
- 更改操作系统的设置,如:操作系统等待时间(cpu切换调度时间)
计算机存储结构
CPU Cache的简单示意图
从CPU到 | 大约需要的CPU周期 | 大约需要的时间(单位ns) |
寄存器 | 1 cycle | |
L1 Cache | ~3-4 cycles | ~0.5-1 ns |
L2 Cache | ~10-20 cycles | ~3-7 ns |
L3 Cache | ~40-45 cycles | ~15 ns |
跨槽传输 | ~20 ns | |
内存 | ~120-240 cycles | ~60-120ns |
1.3 选择正确的平台并评估系统性能
1.3.1 选择正确的cpu架构
cpu架构的概念:CPU架构是CPU厂商给属于同一系列的CPU产品定的一个规范,主要目的是为了区分不同类型CPU的重要标示。目前市面上的CPU分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另一个是以IBM、ARM为首的精简指令集CPU。两个不同品牌的CPU,其产品的架构也不相同,例如,Intel、AMD的CPU是X86架构的,而IBM公司的CPU是PowerPC架构,ARM公司是ARM架构。
- 多线程不一定比单线程执行的更快,因为线程切换需要时间
- 上下文切换次数和时长的测试工具:lmbench3(检测时间)、vmstat(检测次数)
- 减少上下文切换的方法:
- 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换
- 使用最少线程:避免创建不必要的线程,任务较少时,多余的线程会处于等待状态
- CAS算法,java的Atomic包使用CAS算法来更新数据,而不需要使用锁
- 无锁并发编程:例如将数据按照一定的算法进行取模分段,不同的线程处理不同段的数据
1.3.2 评估系统性能
- cpu切换时间
- cpu高速缓存命中