Java性能优化随记

性能调优是我们在日常开发过程中必然会遇到的一个问题,本文总结了常见的性能相关的指标和影响因素,以及常见的调优方法,如有不合理之处还请各位指出。

1.了解性能

1.1性能指标

一般情况下我们会从以下维度去衡量负责系统的性能优劣:

    响应时间:有AVG、TP99、MAX等多个指标,衡量一段特定时间内不同程度的请求处理时长;

    吞吐量:有QPS、TPS等多个指标,衡量单位时间内能够处理请求的数量;

    资源消耗:有CPU使用率、平均负载、磁盘I/O等多个指标;

    错误率:很多开发同学都会忽略这个指标,但如果一个系统吞吐量或者响应时间的提升是以错误率上升为代价,那么这是没有意义的。

1.2 性能的影响因素

资源是影响性能的决定性因素。从本质上说一次请求就是用特定的资源换取对请求的处理,对服务器来说通常需要消耗的资源包括CPU、内存、网络IO、磁盘IO等,具体如下:

性能影响因素分析图

2.性能诊断工具

工欲善其事,必先利其器。在讨论具体讨论性能优化的方法之前,先来看下我们有哪些可用的性能诊断工具。

2.1 常用系统命令/工具

常见的性能诊断命令主要分为两层:OS 层面和 Java 应用层面(包括应用代码诊断和 GC 诊断)

常用性能诊断命令总结

3. 性能优化的SOP

1.确立目标和现状分析

    目标可以分为两个部分:一是优化对象;二是要在什么指标上达到什么样的结果,比如查询服务达到单机QPS 2000且AVG在50ms以内。

在具体优化前,应该了解下整体现状,包括现有系统架构、当前性能指标以及与目标的实际差距。

对于已经在线上运行的系统,现有的性能指标又会影响到整个优化目标的设立。

3.2 发现瓶颈

对于已上线且面对高并发场景的系统,一般性能瓶颈可以通过日常运维过程中通过监控平台上峰值流量时的表现或者异常记录从而发现:比如log4j2在AOP情况下error记录堆栈信息时会因为争抢锁而导致应用性能明显下降。

对于未上线或流量不足的系统,那么通常只能通过压测的方式来明确当前性能指标和发现问题,由于压测不再本次讨论范围内,故不做阐述。

3.3 分析并解决

性能问题分析如同雾里看花,根因(RootCause)需要开发人员耐着性子一层一层地去揭示,有些问题甚至不是业务代码本身引入的,而是物理机器抖动或者中间件所引入的。问题分析可以说是即考验RD技术功底和经验,又磨砺耐心。好在日常实际工作中,问题分析的难易度也遵守二八原则:八成的性能问题都能通过较为定式的套路分析得出原因,剩下两成的疑难杂症就需要依靠团队老司机、外部工具、甚至奇技淫巧才能得以解决。

定位瓶颈应该由大到小,先确定是项目本身的瓶颈、DB还是缓存。然后再进一步分析具体是哪个模块、哪个原因。要想能够快速分析问题,前面介绍的各类诊断工具需要熟练掌握,并且应该通过自己摸索、积累建立一套属于自己分析的SOP。

结合日常工作经验将常见的性能问题进行了归类,如下:

性能问题分类

3.4 验证效果

应该尽可能还原发现问题时的现场,这里包括请求量级、压测数据、上下游机器配比、机器配置(CPU\MEM\DISK)、机房分布等等。只有相同的现场在才能最大程度证明优化的效果,两者差距越小,那么优化的效果才越是可信。比如优化CPU密集型项目:发现问题时所在机器是4核的,效果验证时随手选了8核,那么就很难辨别是因为优化还是因为提升了机器配置提升解决的问题。

具体验证方式包括:

直接观察指标:适用于访问量、AVG、TP999、CPU等现有监控平台直接提供指标的优化后验证。

单机吞吐量:压测。如果对于压测数据没有特殊的要求并且线上流量足够,可以直接通过调整集群中机器的负载均衡来验证。否则,就需要按照正规的压测流量在Quake上进行压测。

极端情况的优化:针对问题的不同,可能需要准备专门的数据,专门的时间,甚至专门的机器进行验证。

如果验证效果后整体未能达到预期目标,那么应该去发现新的瓶颈进行新一轮的优化;如果是该优化点未能有明显效果,那么要重新去分析原有问题,是之前判断错了,还是优化本身没有到位。

3.5 经验输出

性能优化的经验输出,对于团队而言,无论是作为日后相同问题解决方案的历史依据,还是作为新人培训的材料都大有裨益。具体可以包括:

针对一些典型的性能问题或者较为少见的问题应该及时文档化,作为技术沉淀将排查过程、分析思路、解决方案逐一记录下来。

4.性能优化的另一个思路:链路优化

当系统性能优化成本较大甚至已经达到极限的情况下,不妨换一个思路:在支撑同样业务目标的情况下,对链路进行梳理、重构以减少外部对瓶颈资源的访问量,我们将这类优化统称为链路优化。

4.1 明确瓶颈

链路优化是一个成本较高的手段,通常不会发生在整个优化任务的早期。当你选择该手段时,往往已经明确系统瓶颈了。一方面,系统瓶颈通常出现在整个链路的最底层;另一方面,绝大多数的业务系统所在集群具备水平扩展的能力,因此数据库是最为常见的系统性能瓶颈

4.2 范围选定

通常情况下一个完整的业务场景请求链路是非常长的,即使不考虑前端团队,仅后端就能横跨多个团队,十几个甚至几十个项目。链路优化范围越是大,成本越是高、周期越是长!如果一股脑进行全链路优化,那么项目将会变得难以控制。因此,建议优化范围从瓶颈出发,由小到大,如果小范围难以达到效果,再进一步扩大范围,逐层递进。

4.3 梳理现状

这是整个链路优化中最为核心重要的环节,后续的所有优化都将建立在梳理后业务和系统现状的认知之上。要得到如下结果:

完整的调用链路图;

链路中各应用间调用的放大系数,最终推出算出对瓶颈资源的放大;

各应用间调用业务意义。

4.4 分析与优化

链路分析的方法本身不难,就是针对每次调用问两个问题:1.这次调用是否多余?2.这次调用是否可以合并?

何谓多余?比如每个业务活动已经停止了,但是上游依旧每次都来查询。又比如业务校验需要查询DB,而这个校验在每一层都做了,那么可以适当牺牲校验的前置性或者信赖上游舍去其中一些校验,当然这个要看具体的业务场景来定。

参考:https://blog.csdn.net/moakun/article/details/80660518

你可能感兴趣的:(Java性能优化随记)