线上排查步骤

CPU - 使用jstack分析cpu问题

找出使用率最好进程id和最高线程id,看它的堆栈信息。

1、找出最高进程号。top 或 jps。如:12480

2、获取每个线程的cpu情况。

top -H -p pid来找到cpu使用率比较高的一些线程.如 top -H -p 12480 。 找到线程号12775.

3、将10进制线程号转16进制来查找堆栈信息

[admin@cr ~]$ printf '%x\n' 12775
31e7

4、执行 jstack <pid> | grep -A 10 <thread ox16 id> 。得到该线程堆栈所在行的最后10行信息。

例如:jstack 12480 | grep -A 10 31e7

jstack 12480 | grep -A 10 31e7 >> info.log 输出到文件中查看。

[admin@node0 logs]$ cat info.log | grep "java.lang.Thread.State" | sort -nr | uniq -c

来对jstack的状态有一个整体的把握,如果WAITING之类的特别多,那么多半是有问题啦。

5、查找日志排查存在问题代码。

频繁gc - jstat

使用jstat -gc pid 1000命令来对gc分代变化情况进行观察,1000表示采样间隔(ms),S0C/S1C、S0U/S1U、EC/EU、OC/OU、MC/MU分别代表两个Survivor区、Eden区、老年代、元数据区的容量和使用量。YGC/YGT、FGC/FGCT、GCT则代表YoungGc、FullGc的耗时和次数以及总耗时。

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT   
 0.0   2048.0  0.0   2048.0 608256.0 63488.0   356352.0   120276.6  190032.0 182010.9 23040.0 20406.7    127    1.320   0      0.000  16      0.177    1.497
 0.0   2048.0  0.0   2048.0 608256.0 63488.0   356352.0   120276.6  190032.0 182010.9 23040.0 20406.7    127    1.320   0      0.000  16      0.177    1.497
看gc日志分析案例

[ParNew: 1679677K->1878K(1887488K), 0.0176620 secs] 2204253K->526489K(6753536K), 0.0178770 secs] [Times: user=0.07 sys=0.00, real=0.02 secs]
[ParNew: 1679702K->2122K(1887488K), 0.0184380 secs] 2204313K->526767K(6753536K), 0.0186610 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
[ParNew: 1679946K->2104 K(1887488K), 0.0166490 secs] 2204591K->526796 K(6753536K), 0.0168640 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
[ParNew: 1679928 K->1646K(1887488K), 0.0174360 secs] 2204620K->526439 K(6753536K), 0.0176530 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]

[GC(Young GC)2017-06-02T15:10:29.874+0800: 68770.091: [ParNew()使用ParNew作为年轻代的垃圾回收): 1679928 K(年轻代垃圾回收前的大小)->1646K年轻代垃圾回收以后的大小)(1887488K)(年轻代的总大小), 0.0174360 secs(回收时间)]] 2204620K(堆区垃圾回收前的大小)->526439K(堆区垃圾回收后的大小)(6753536K(堆区总大小), 0.0176530 secs(回收时间)] [Times: user=0.06Young GC用户耗时) sys=0.00(Young GC系统耗时), real=0.02 secsYoung GC实际耗时)]

从最后一条GC记录中我们可以看到 Young GC回收了 1679928-1646=1678282 K的内存
Heap区通过这次回收总共减少了 2204620-526439= 1678181 K的内存。

1678282-1678181=101K说明通过该次Young GC有101K的内存被移动到了Old Gen
我们来验证一下

在最后一次Young GC的回收以前 Old Gen的大小为 526796(倒数第二条堆内存)-2104=524692 <br/>
回收以后Old Gen的内存使用为 526439-1646=524793
Old Gen在该次Young GC以后内存增加了 524793-524692=101K 与预计的相符

​​​​​​Java应用频繁FullGC分析-阿里云开发者社区

上下文切换

针对频繁上下文问题,我们可以使用vmstat命令来进行查看

vmstat pid

[admin@node0 ~]$ vmstat 2934
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 288692  77592 5330940    0    0     7  1078    0    0  2  1 97  1  0

cs(context switch)一列则代表了上下文切换的次数

如果我们希望对特定的pid进行监控那么可以使用 pidstat -w pid命令,cswch和nvcswch表示自愿及非自愿切换。

磁盘

查看文件系统状态

[admin@node0 ~]$ df -hl
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        79G   68G  7.6G  90% /

iostat查看磁盘性能

[admin@node0 ~]$ iostat -d -k -x
Linux 3.10.0-1062.9.1.el7.x86_64 (node0)        02/11/2022      _x86_64_        (8 CPU)

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
vda               0.00     2.91    0.59    4.05    16.05    44.23    25.96     0.01    3.45    1.16    3.78   0.14   0.07
最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及wrqm/s分别表示读写速度,一般就能帮助定位到具体哪块磁盘出现问题了

lsof命令来确定具体的文件读写情况lsof -p pid

[admin@credit-dev-1 ~]$ lsof -p 23387
COMMAND   PID  USER   FD      TYPE             DEVICE  SIZE/OFF     NODE NAME
java    23387 admin  cwd       DIR              253,1      4096  1052949 /home/admin/deploy/flow-analysis

内存

1.先检查内存使用情况。free  主要包括OOM、GC问题和堆外内存。

堆内内存

内存问题大多还都是堆内内存问题。表象上主要分为OOM和StackOverflow。

OOM

JMV中的内存不足,OOM大致可以分为以下几种:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
这个意思是没有足够的内存空间给线程分配java栈,基本上还是线程池代码写的有问题,比如说忘记shutdown,所以说应该首先从代码层面来寻找问题,使用jstack或者jmap。如果一切都正常,JVM方面可以通过指定Xss来减少单个thread stack的大小。另外也可以在系统层面,可以通过修改/etc/security/limits.confnofile和nproc来增大os对线程的限制

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
这个意思是堆的内存占用已经达到-Xmx设置的最大值,应该是最常见的OOM错误了。解决思路仍然是先应该在代码中找,怀疑存在内存泄漏,通过jstack和jmap去定位问题。如果说一切都正常,才需要通过调整Xmx的值来扩大内存。

Caused by: java.lang.OutOfMemoryError: Meta space
这个意思是元数据区的内存占用已经达到XX:MaxMetaspaceSize设置的最大值,排查思路和上面的一致,参数方面可以通过XX:MaxPermSize来进行调整

Stack Overflow

栈内存溢出,这个大家见到也比较多。
Exception in thread "main" java.lang.StackOverflowError
表示线程栈需要的内存大于Xss值,同样也是先进行排查,参数方面通过Xss来调整,但调整的太大可能又会引起OOM。

使用JMAP定位代码内存泄漏

JMAP

jmap -dump:format=b,file=filename pid来导出dump文件

工具地址 : Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

通过mat(Eclipse Memory Analysis Tools)导入dump文件进行分析,内存泄漏问题一般我们直接选Leak Suspects即可,mat给出了内存泄漏的建议。另外也可以选择Top Consumers来查看最大对象报告。和线程相关的问题可以选择thread overview进行分析。除此之外就是选择Histogram类概览来自己慢慢分析。

  • Histogram可以列出内存中的对象,对象的个数以及大小。
  • Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
  • Top consumers通过图形列出最大的object。
  • Leak Suspects通过MA自动分析泄漏的原因。

另一方面,我们可以在启动参数中指定-XX:+HeapDumpOnOutOfMemoryError来保存OOM时的dump文件。

gc问题和线程

gc问题除了影响cpu也会影响内存,排查思路也是一致的。一般先使用jstat来查看分代变化情况,比如youngGC或者fullGC次数是不是太多呀;EU、OU等指标增长是不是异常呀等。
线程的话太多而且不被及时gc也会引发oom,大部分就是之前说的unable to create new native thread。除了jstack细细分析dump文件外,我们一般先会看下总体线程,

通过pstree -p pid |wc -l

[admin@node0 ~]$ pstree -p 17218 |wc -l
93

或者直接通过查看/proc/pid/task的数量即为线程数量
[admin@node0 ~]$ ls -l /proc/17218/task | wc -l
95

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值