常见线上问题的排查思路

常见线上问题排查思路与工具

文章列举的案例都很简单,线上情况往往要复杂的多的多,旨在提供一些思路和工具参考。

OOM

概念

OOM,即java.lang.OutOfMemoryError,官方的定义:当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error。

常见的OOM类型

●堆溢出:-Xmx与-Xms
○大对象或大量小对象:应用程序创建了大量的对象,超过了JVM堆内存的限制。查询数据库未加限制条件
○内存泄漏:不再需要的对象未能被垃圾回收器及时回收,长期占用内存。ThreadLocal
●栈溢出:-Xss
○递归调用或深度嵌套调用
○过多线程:创建了大量线程,每个线程都有固定的栈大小,过多的线程会耗尽系统内存
●运行时常量池溢出:-XX:PermSize与-XX:MaxPermSize
●方法区溢出:应用程序动态加载大量的类
●直接内存溢出:-XX:MaxDirectMemorySize,NIO使用不当:Java NIO允许直接在堆外分配内存,如果分配过多而未释放,会引发DirectBufferMemory错误

排查

1.dump堆栈文件
●手动dump:jmap -dump:format=b,file=java.hprof ‘java进程PID’
●自动dump:发生OOM时,自动dump当时的堆栈文件,-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/logs/java.hprof

2.分析
●MAT
○Leak Suspects:MAT自动生成可疑泄露点的报告。
○Histogram:哪些对象占用大量内存
○dominator_tree:对象被谁引用
○thread_overview:每个线程当时的方法调用栈
●公司提供的线上Dump分析工具
https://n.alibaba-inc.com/micro/ops/action/JavaDump
https://grace-parser.alibaba-inc.com/heapDump

OOM Killer

现象

未生成java.hprof文件,服务日志无明显异常,进程莫名其妙消失。

概念

Linux内核内存管理使用OOM killer(Out-Of-Memory killer)机制,在系统内存不足时,选择性杀死一些进程以释放内存,以使系统继续运行。

Linux系统OOM
https://ata.atatech.org/articles/11000202936

排查

查询操作系统级的日志

dmesg -T | egrep -i -B100 'killed process'

egrep -i -r 'killed process' /var/log/messages

CPU100%

常见的原因

1.频繁的垃圾收集:如果应用产生大量短暂存活的对象,可能会导致频繁的年轻代垃圾收集,消耗CPU资源。
2.代码bug:无限循环、递归调用
3.计算密集型操作:如加解密、数学计算等

排查

●Jstack
1.top,查找CPU异常的进程
2.top -Hp 进程id,找到具体的线程
3.printf ‘%x \n’ 线程id,查看线程id对应的16进制
4.jstack 进程id | grep 线程id(十六进制) -C 50,定位问题
●Arthas
1.thread,查看各线程CPU占用情况
2.thead 30,其中ID为30的线程,占用95%的CPU,查看线程30的堆栈信息
3.jad --source-only org.example.service.impl.DemoServiceImpl,反编译已加载的类的源码查找问题

公司线上的Arthas工具:https://start.alibaba-inc.com/v2/arthas

性能优化

使用Arthas排查系统性能优化方向,比较常用的功能:trace、火焰图。
●trace
○性能瓶颈定位:通过分析方法调用链路,找出耗时较长的方法,从而定位性能瓶颈。
○优化代码执行路径:通过查看方法调用的频率和耗时,可以优化代码逻辑,提高执行效率。
●火焰图
○CPU热点分析:火焰图可以直观地展示CPU时间的分布情况,找出应用中消耗CPU最多的函数或方法。
○性能优化:火焰图可以快速识别哪些部分的代码消耗了过多的CPU资源,从而指导优化工作。
○线程状态分析:火焰图可以显示线程的堆栈信息,有助于理解线程的活动状态,识别死锁、锁竞争等问题。

排查

●trace
1.trace -E org.example.service.impl.DemoServiceImpl testSlow -n 5 --skipJDKMethod false ‘1==1’,开启接口trace
2.请求接口,得到trace结果
发现DemoServiceImpl#testSlow内部,handleBiz方法执行了2次,耗时2s,queryAuthList耗时4s,remoteGetOrderListFrom耗时4s,queryUser耗时3s,总耗时13s。
3.根据实际进行性能优化如:批量处理、并行调用、异步处理和增加缓存等。
优化后:

针对CompletableFuture的使用及原理,推荐阅读:
https://tech.meituan.com/2022/05/12/principles-and-practices-of-completablefuture.html

●火焰图
1.profiler start --event cpu,开始采样;profiler stop --format html,停止采样,生成 html 格式结果。
2.访问 http://127.0.0.1:8563/arthas-output/,查看采样结果。
Y轴表示调用栈,每一层都是一个函数。顶部就是正在执行的函数,下方都是它的父函数。
X轴表示抽样数,如果一个函数在 x 轴占据的宽度越宽,就表示它被抽到的次数多,即执行的时间越长,每一个格子的宽度可以直接理解为CPU时间占比(其实是采样的数量以及与采样总量的占比)。
火焰图就是看顶层的哪个函数占据的宽度最大。
绿色部分代表Java代码
黄色部分代表JVM C++代码
橙色部分代表内核态C语言代码
红色代表用户态C语言代码
所以重点关注绿色部分

发现DemoServiceImpl#run方法占采样比例最大

层层递进发现DemoServiceImpl#primeFactors方法占比最高,考虑针对其进行性能优化。
推荐安装插件,arthas idea,能够快速的生成一些arthas命令。

扩展

推荐另外一个常用的命令,tt。针对不确定如何复现问题的场景,执行后将会记录方法调用的所有入参、返回值和异常,并能够从多次调用中选择某次调用进行回放(非幂等的方法谨慎操作)。举个例子:
1.tt -t org.example.service.impl.DemoServiceImpl testSlow -n 5,记录DemoServiceImpl#testSlow接下来5次的调用信息。
2.tt -i 1002,查看index为1002的那次调用的详细信息
3.tt -p -i 1002,重放index为1002的那次调用

死锁

概念

Java线程死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者因为同步机制使用不当,造成互相等待对方持有的资源,导致程序无法继续执行的一种情况。

排查

1.jvm,查看当前JVM运行信息,可以看到DEADLOCK-COUNT:2,即2个线程死锁。
2.thread -b,找到当前阻塞其他线程的线程。可以看到Id为61的线程被Id为60的线程阻塞了,再查看这两个线程具体的情况。
3.jad --source-only org.example.service.impl.DemoServiceImpl,反编译查找问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值