总结:测试——分析——优化
一、测试--> 输出,性能测试报告
1、微基准性能测试
精准测试,测试某个模块/方法在不同的实现方式下的性能表现。
2、宏基准性能测试,
综合测试,考虑:测试环境、场景、目标
环境,模拟真实线上环境
场景,排除干扰因素,包含:其他服务、第三方接口
目标,逐渐增加并发数,测试TPS(最大的每秒事务请求数),并观察:吞吐量、响应时间、cpu、内存、磁盘IO、网络IO使用率等
输出“性能测试报告”,包含以下指标:
测试接口的平均/最大/最小吞吐量
响应时间
cpu/内存/磁盘IO/网络IO的资源使用率
jvm的gc频率
干扰因子
1、热身问题
现象,第一次请求接口比较慢,后面请求越来越快
分析,.java文件被编译为.class文件后,需要解释器转化为机器码 才能运行。某个方法/代码块被经常执行,则被虚拟机认定为“热点代码”。为了提高执行效率,虚拟机通过编译器把这些代码编译为与本地平台相关的机器码,并进行各个层次的优化,后存储在内存中,之后运行时,直接从内存中获取。因此,刚开始运行时比较慢(虚拟机花长时间全面优化代码),越往后越快
2、测试结果不稳定
即使测试的数据集一样,结果也可能有差异。考虑,机器中其他进程影响,网络波动,jvm垃圾回收等
可以通过多次测试,求平均值/统计曲线图,保证平均值在合理范围之内即可。
3、多jvm的影响
任意一个jvm都拥有整个系统的资源使用权,尽量保证线上环境一台机器中部署一个jvm。
二、分析 (自下而上)
按照下面顺序,分析“性能测试报告”
1、计算机资源:cpu、内存、磁盘IO、网络IO 是否存异常?并查看异常日志
2、容器:web容器
3、jvm层面:垃圾回收频率、内存分配情况
4、应用服务器:java编码问题、读写数据瓶颈
三、优化(自上而下)
1、应用层的调优
1)优化代码,因为资源耗尽而暴露。
代码问题,如:内存溢出/jvm内存用完,引发jvm频繁垃圾回收,导致cpu1000%,又消耗系统cpu资源
非代码问题,如:for循环遍历LinkedList。每次循环都要遍历一次链表,降低读的效率。
2)优化设计,利用设计模式优化业务层/中间层的代码设计,精简代码,提高性能
如,单例模式,共享创建的兑现,减少频繁创建、销毁带来的性能消耗
3)优化算法
如,查找算法
4)时间换空间,适用于对存储容量要求苛刻,单查询速度不作要求的场景
如,String的interm方法,将重复率高的数据存储在常量池中,节省存储空间。(常量池使用HashMap实现,不能存储过多数据,否则性能下降)
5)空间换时间,提升访问速度
如,分库分表。mysql单表数据上千万时,读写性能明显下降。
2、系统调优
1)jvm调优,合理设置jvm内存空间、垃圾回收策略
若业务中创建大量的大对象,可以通过设置将大对象直接放入 老年代,减少年轻代频繁发生小的垃圾回收(minor gc),减少cpu占用时间
2)组件调优
如,web容器,线程池的设置
3)操作系统调优,优化内核参数
四、兜底策略!
无论系统调优多么好,总会存在承受极限,通过兜底方法,保证系统稳定性。
1、限流熔断。设置最大访问限制(参考tps值),友好返回没有成功的请求。
2、扩容
1)智能横向扩容。当访问量超过指定阈值,自动新增/减少机器。
2)提前扩容。常用于 高并发系统。
如,瞬间的抢购业务,要提前加机器;瞬间大量请求,即使横向扩容成功了,抢购也结束了。
推荐,Kubernetes作为Docker容器的容器管理器,可以实现智能 横向扩容+ 提前扩容Docker服务
总结,
任何调优都需要结合场景,明确已知问题和性能目标,不能为了调优而调优,否则带来风险和bug。
调优策略千变万化,但思想和核心都一样的。都是从业务调优——编码调优——系统调优
还没有评论,来说两句吧...