Java程序性能优化

性能优化流程

资源使用 ---》 访问缓慢 ---》 优化瓶颈 ---》 达到性能目标

主体就是:降低响应时间,提高吞吐量

性能指标

  • 响应时间:一次操作完成的时间。包括用于等待和服务的时间,也包括用于返回结果的时间

  • 吞吐量:在数据传输中描述速度,例如字节/秒,在事务系统内中,指操作的速度,每秒操作数

  • 使用率:对于服务所请求的资源,描述在给定时间内的繁忙程度。例如,内存使用率

  • 饱和度:某一资源无法满足服务的排队工作量。

  • 错误:如果资源消费时发生错误,往往意味着出现过载情况

  • 瓶颈:在系统性能中,限制系统性能的资源。识别和移除系统瓶颈是性能优化的主要工作。

响应时间和吞吐量是核心性能指标,响应时间是一次操作完成的时间,吞吐量是每秒钟完成的事务数。

使用率、饱和度、错误是系统组成对象的负载描述,性能关注点按照重要程度依次是错误、饱和度、使用率。

瓶颈是制约系统性能的资源,性能优化的目标就是找到和优化性能瓶颈。

性能问题的描述
这个要求客户讲述自己的版本,访问链接,同时对性能进行准确的描述,比如一个请求的响应时间等。这点非常重要。

资源的种类

硬件资源:磁盘,CPU,内存,缓存,网络

软件资源:文件,进程,线程池,互斥锁,连接池,线程

资源是有限的

获取资源使用的应该遵守原则

  • 尽可能晚地获取资源

  • 尽可能早地释放资源

  • 尽可能少地分配/访问/移动资源

资源的分析方法
资源使用分析法

监控资源的各种指标,发现资源可能存在的瓶颈。重点关注资源的使用率、饱和度、错误指标。常用于总体性能问题以及特定范围的性能问题。

时间划片法
检查一项工作所完成的时间,把时间划分成小的时间段,再对最大延时时间段做再次的划分,最后定位并量化问题的根本原因。会深入到软件栈的各层来找到延时的原因。一个大的步骤可以进一步下钻,分解成更细的步骤并分析优化。

在分析资源前应该了解一个系统的部署架构,比如一个网站接受http请求,传送到nginx服务器,然后分发到K8S的负载均衡器,再传给K8S的业务容器中调用redis,mysql,mq等容器,处理完成后,原地返回。

常见的性能问题

慢sql,频繁地读取数据库,低效的代码,GC,并发异常,错误的配置

网络分析

ifconfig命令,查看RX,TX信息栏

 RX errors: 总收包的错误数量

 RX dropped: 进入到Ring Buffer的帧在拷贝到内存的过程中被丢弃。

 RX overruns: 增大意味着数据包没到 Ring Buffer 就被网卡物理层给丢弃。

 RX frame: 表示 misaligned 的 frames。

 collisions 则表示由于 CSMA/CD 造成的传输中断。

对于 TX 的来说,出现上述 counter 增大的原因主要包括 aborted transmission, errors due to carrirer, fifo error, heartbeat erros 以及 windown error,而 collisions 则表示由于 CSMA/CD 造成的传输中断。


MTU: Maximum Transmit Unit,最大传输单元,即物理接口(数据链路层)提供给其上层(通常是IP层)最大一次传输数据的大小;以普遍使用的以太网接口为例,缺省MTU=1500 Byte,这是以太网接口对IP层的约束,如果IP层有<=1500 byte 需要发送,只需要一个IP包就可以完成发送任务;如果IP层有> 1500 byte 数据需要发送,需要分片才能完成发送,这些分片有一个共同点,即IP Header ID相同。


MSS:Maximum Segment Size ,TCP提交给IP层最大分段大小,不包含TCP Header和 TCP Option,只包含TCP Payload ,MSS是TCP用来限制application层最大的发送字节数。如果底层物理接口MTU= 1500 byte,则 MSS = 1500- 20(IP Header) -20 (TCP Header) = 1460 byte,如果application 有2000 byte发送,需要两个segment才可以完成发送,第一个TCP segment = 1460,第二个TCP segment = 540。

这是因为数据链路层--》IP层--》传输层--》应用层


#### 传输层

tcpdump -i any -nn -G 1800 -s 128 -Z root port 3307 and host 172.17.32.43 -w %Y_%m%d_%H%M_%S.cap

-G 30 间隔30秒生成文件
-Z 需要创建新文件时启用
-s 限定数据大小,在忽略网络数据内容时使用。
-X 显示包的内容

例子:
1、不要抓广播 !broadcast
2、过滤MAC地址, ether host 00:80:**** 如果IP与端口不停变动,则启用MAC抓包
3、IP地址过滤: host 192.168.0.120 可以考虑方向
4、端口:!port 80 不抓80
5、协议: arp、icmp

wireshark
在win10平台,可以与代码联调,但是要启动长链接

高级功能:
1、数据流追踪
作用:将TCP、UDP、SSL等数据流进行重组并完整呈现出来
操作方法:Analyze->Follow TCP stream 跟踪tcp流

2、专家信息说明
作用:对数据包中的特定状态进行警告说明,包括错误、警告、注意、对话
操作方法:Analyze->Expert Info

3、统计摘要
作用:对抓取的数据包进行全局统计
路径:Statistics->Summary

应用层

谷歌http分析,前端性能分析:Chrome->开发者工具->Perfomance页签 ->Record -> 网页操作->Stop

curl 测量网络延时,计算出各种阶段的花费时间

Fiddler分析请求


==总结== 数据链路层: ifconfig , ethtool 查看传输速度speed和传输介质

IP层: arp -n, route -n ,ping , tracert tracepath 判断能否直达,关注TTL和跟踪路径

传输层: TCP握手和抓包,tcpdump

nginx参数配置 非常重要,记录upstream_connect_time建立连接时间,upstream_response_time服务端处理时间 后面一个参数即服务端处理业务的时间

nginx 如果不开启HTTP2.0,那么也要求开启长连接 keepalive 1000

ping命令关注TTL,时间 考虑访问网站的时间和跳转次数,以及丢包率

进程状态分析--内存

外在表现: 请求长时间停顿,请求超时,网关504错误

根本原因: Full GC; Stop the World时间超过ngnix读取时间;OOM的发生;JVM没有启动,没有指定xmx

寻踪原因: 容器内查看死去应用 docker inspect 关注OOMKilled 和 CpuShares参数;docker stats 监控运行中的容器负载,CPU可以超过100%; docker logs 查看容器的日志

Java查看内存资源内置的工具,pmap等,尤其是GC日志查看

依据Java内存结构分配JVM允许内存空间,最好不设置jvm运行内存空间的最大值,这等于限制Java

进程hang住后,无法用jstack dump栈信息,执行jstack -F后进程恢复服务,minorGC结束。

关注Java Head堆内存和 非堆内存

非堆内存有元数据区,Java栈,本地栈,常量池,线程空间,GC

top -p pid 查看进程内存占用量 , 有两个内存量,虚拟内存和物理内存
物理内存即系统分配给进程使用的内存空间

VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA

容器内添加-XX:NativeMemoryTracking=detail 参数解析内存占用


/jdk/bin/jcmd 1 VM.native_memory scale=MB 命令查看虚拟机各区内存占用情况

Java GC分析

事后分析,在线分析工具https://gceasy.io/ 和 Gcviewer ,GC分析一般是看老年代和新生代的空间是否充足等,不充足补足足够的内存空间

Gc日志主要分析full GC情况

top –H –p 1 ; 一般pid<100为gc线程

如果GC线程无法使用jmap等命令,hang住了,可以使用 jstack –F –m

大堆(Xmx>=4G)
推荐使用G1:-XX:+UseG1GC -XX:G1ReservePercent=5
小堆(Xmx<4G)
推荐使用吞吐量优先方式,即默认的GC方式。
查看所有参数的方法
$java -XX:+PrintFlagsFinal -version

OOM问题分析

OOM问题是非常常见的,主要原因也是那几个原因,比较好解决

参考链接

可以在容器内设置挂载目录,做数据映射,容器启动后执行 jdk/bin/jmap -dump:live,format=b,file=/容器内挂载路径/fin_20200822.bin 当发生OOM问题,记录到映射区

MAT工具
[参考链接]https://zhuanlan.zhihu.com/p/56110317
dump文件分析

JProfiler类似mat在IDEA运行的工具

进程行为分析--线程

识别线程

Monitor、Jstack、Arthas

使用后面两个

1、堆栈的局部信息:调用层级关系、锁与等待

2、一次堆栈的全局信息:锁争用、大多数线程在干什么、线程总数

3、多个堆栈的前后对比:方法是否长期执行、长期等待某个资源

监控线程,用上述的三个工具

阿里工具使用介绍
官方下载地址
火焰图,Jprofiler工具查看

Arthas的使用

在win系统使用Java自带的VisualVM工具,查看Java进程ID

下载好Arthas,解压压缩文件,
as.bat pid

IDEA开发工具,搭配插件使用,下载地址,这个插件只能帮你制作命令,你需要到选中方法然后点击工具栏,制作命令

命令讲解

  1. dashboard 查看进程的简要报道

  2. thread 1 将打印 ID 为 1 的线程的堆栈,通常是主函数线程。 $thread 1 | grep 'main('

  3. jad demo.classname 命令反编译类

  4. sc -d *classname 可以打印JVM中加载的类详细信息

  5. vmtool 可以获取JVM中存活的某个类的实例或者强制GC
    vmtool --action getInstances --className java.lang.String --limit 10
    vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext
    vmtool --action forceGc

  6. monitor 监控方法的执行情况
    monitor -c 5 demo.MathGame primeFactors ,-c 表示方法执行几次为一个周期,一个周期统计一次情况

  7. watch 可以观察方法的指定调用情况,可以查看方法的 返回值,异常,方法参数 ,默认的观察维度是{params, target, returnObj} 参数,执行类,返回值,可以观察方法执行前,执行后,异常发生前,异常发生后的信息,默认在方法执行后
    [x:] 指定输出结果的属性遍历深度,默认为 1 ,如果参数是数组,x=2 能观察到数组里面的内容

watch demo.MathGame primeFactors -x 2
watch demo.MathGame primeFactors "{params[0],throwExp}" -e -x 2 观察第一个参数和抛出异常
watch demo.MathGame primeFactors 'target' 观察对象的属性

  1. trace 方法内部调用路径,并输出方法路径上的每个节点上耗时,

trace demo.MathGame run -n 1 n为捕获结果次数
trace --skipJDKMethod false demo.MathGame run 方法调用栈默认是不带JDK的方法,但是加上相关参数解除限制

  1. stack 输出当前方法被调用的调用路径,很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。

stack demo.MathGame primeFactors

  1. tt 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测,主要观察方法是否返回异常或者正常返回
    tt -t demo.MathGame primeFactors -t 这个参数的表明希望记录下类 *Test 的 print 方法的每次执行情况
IS-RET 方法是否以正常返回的形式结束
IS-EXP 方法是否以抛异常的形式结束

解决方法重载
tt -t *Test print params.length==1
tt -t *Test print 'params[1] instanceof Integer'
tt -t *Test print params[0].mobile =="13989838402"

tt 命令由于保存了当时调用的所有现场信息,所以我们可以自己主动对一个 INDEX 编号的时间片自主发起一次调用
tt -l 展示全部的数据
tt -s 'method.name=="primeFactors"'
tt -i 1003 查看具体的一栏
tt -i 1004 -p 发起一次调用,因为保留了信息,但是是arthas发起的调用

  1. profiler 生成应用热点的火焰图,格式profiler action [actionArg]

actionArg属性名模式 [i:]采样间隔(单位:ns)(默认值:10'000'000,即10 ms) [f:]将输出转储到指定路径 [d:]运行评测指定秒 [e:]要跟踪哪个事件(cpu, alloc, lock, cache-misses等),默认是cpu
一次采样生产火焰图 profiler start,profiler getSamples,profiler status, profiler stop,profiler stop --file /tmp/output.svg, profiler stop --format html,profiler resume 默认是CPU事件
trace demo.MathGame run '#cost > 10' watch/stack/trace这个三个命令都支持#cost,关注时间过长的或者过短的
通用的选项 -n 执行次数 '#cost > 10' 执行时间 '{params,target,returnObj,throwExp' 常用的观察维度 'params[1].toLowerCase().contains("from t_sec_user ")' -n 1 更加复杂的参数
posted @ 2021-09-29 21:08  lfcom  阅读(214)  评论(0编辑  收藏  举报