原文详见https://ricstudio.top/archives/java-online-question-probe
不管出现任何问题,优先级最高的永远是恢复服务,保留下当时的异常信息(内存dump、线程dump、gc log等等,在紧急情况下甚至可以不用保留,等到事后去复现),等服务正常,再去复盘问题
常见问题: Cpu 利用率高\飙升
常见原因:
- 频繁Gc
- 死循环,线程阻塞 ,io wait…etc
定位问题
传统方法top
针对的是Java进程启动开始到现在的cpu占比情况
- top 命令查看系统进程监控, hp按照线程排序 hm根据内存排序
- top -Hp pid 定位Cpu最好的线程
- printf ‘0x%x’ tid 线程 id 转化 16 进制
- jstack pid | grep tid 找到线程堆栈
jstack 12816 | grep 0x3211 -A 30
top 命令显示的指示符的含义
| 指示符 | 含义 | | —- | —- | | PID | 进程id | | USER | 进程所有者 | | PR | 进程优先级 | | NI | nice值。负值表示高优先级,正值表示低优先级 | | VIRT | 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES | | RES | 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA | | SHR | 共享内存大小,单位kb | | S | 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 | | %CPU | 上次更新到现在的CPU时间占用百分比 | | %MEM | 进程使用的物理内存百分比 | | TIME+ | 进程使用的CPU时间总计,单位1/100秒 | | COMMAND | 进程名称(命令名/命令行) |
简化top的工具
show-busy-java-threads,但我没用过
阿里云的arthas
arthas这种是一段采样间隔内,当前JVM里各个线程所占用的cpu时间占总cpu时间的百分比。
如果没有安装,可以线上安装.
curl -O https://arthas.gitee.io/arthas-boot.jar # 下载
- dashboard :系统实时数据面板, 可查看线程,内存,gc 等信息
- thread :查看当前线程信息,查看线程的堆栈,如查看最繁忙的前 n 线程
- getstatic:获取静态属性值,如 getstatic className attrName 可用于查看线上开关真实值
- sc:查看 jvm 已加载类信息,可用于排查 jar 包冲突
- sm:查看 jvm 已加载类的方法信息
- jad:反编译 jvm 加载类信息,排查代码逻辑没执行原因
- logger:查看logger信息,更新logger level
- watch:观测方法执行数据,包含出参、入参、异常等
- trace:方法内部调用时长,并输出每个节点的耗时,用于性能分析
-
常见现象
发现cpu最高 的是Gc线程
GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007fd99001f800 nid=0x779 runnable
GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007fd990021800 nid=0x77a runnable
GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007fd990023000 nid=0x77b runnable
GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007fd990025000 nid=0x77c runnab
排查方法:
方法a : 查看gc 日志 (需要记得开启)
- 方法b : jstat -gcutil 进程号 统计间隔毫秒 统计次数(缺省代表一致统计
- 方法c : 如果所在公司有对应用进行监控的组件当然更方便(比如Prometheus + Grafana)
获取到gc日志之后,可以上传到GC easy帮助分析,得到可视化的图表分析结果。
发现cpu最高的是业务线程
- 等待内核态锁,如 synchronized
- jstack -l pid | grep BLOCKED 查看阻塞态线程堆栈
- dump 线程栈,分析线程持锁情况。
- arthas提供了thread -b,可以找出当前阻塞其他线程的线程。针对 synchronized 情况
- 查询是否有代码死锁: jstack –l pid | grep -i –E ‘BLOCKED | deadlock