Linux——线上故障排查(四)

前言

线上故障主要会包括cpu、磁盘、内存以及网络问题,但大多数故障不止是一个层次的问题,所以要依次排查。

CPU

一般来讲我们首先会排查cpu方面的问题。cpu异常往往还是比较好定位的。原因包括业务逻辑问题(死循环)、频繁gc以及上下文切换过多。而最常见的往往是业务逻辑(或者框架逻辑)导致的,可以使用jstack来分析对应的堆栈情况。

使用jstack分析cpu问题

  1. 首先找到对应进程的pid

    pgrep hello / lsof -i:8089

  2. 根据pid找到cpu使用率较高的几个线程

    top -H -p pid

  3. 然后将占用最高的pid转换为16进制nid

    printf ‘%x\n’ pid

  4. 直接在jstack中找到相应的堆栈信息

    jstack pid |grep ‘nid’ -C5 –color

    Linux——线上故障排查(四)_2021-01-07-14-16-09.png

    cat jstack.log | grep “java.lang.Thread.State” | sort -nr | uniq -c

    如果WAITING之类的特别多,那么多半是有问题啦。

频繁GC

当然我们还是会使用jstack来分析问题,但有时候我们可以先确定下gc是不是太频繁,对gc分代变化情况进行观察

jstat -gc pid 1000

Linux——线上故障排查(四)_2021-01-07-14-18-52.png

如果看到gc比较频繁,再针对gc方面做进一步分析,具体可以参考一下gc章节的描述。

频繁上下文切换

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

vmstat 1

Linux——线上故障排查(四)_2021-01-07-14-22-58.png

cs(context switch)一列则代表了上下文切换的次数。如果要对特定pid进行监控。

pidstat -w pid

Linux——线上故障排查(四)_2021-01-07-14-25-11.png

cswch和nvcswch表示自愿及非自愿切换。

磁盘

磁盘问题和cpu一样是属于比较基础的。首先是磁盘空间方面,我们来查看文件系统状态

df -hl

Linux——线上故障排查(四)_2021-01-07-14-26-05.png

更多时候,磁盘问题还是性能上的问题。我们可以通过iostat来进行分析:

iostat -d -k -x

Linux——线上故障排查(四)_2021-01-07-14-28-47.png

最后一列%util可以看到每块磁盘写入的程度,而rrqpm/s以及wrqm/s分别表示读写速度,一般就能帮助定位到具体哪块磁盘出现问题了。

使用iotop找出使用磁盘繁忙的进程pid

Linux——线上故障排查(四)_2021-01-07-14-36-25.png

iotop -Po 参数P表示只显示进程,不显示线程,参数o表示只显示正在进行io操作的进程

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

内存

内存问题排查起来相对比CPU麻烦一些,场景也比较多。主要包括OOM、GC问题和堆外内存。一般来讲,我们会先用free命令先来检查一发内存的各种情况。

Linux——线上故障排查(四)_2021-01-07-14-52-19.png

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

内存不足报错情况

  1. 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对线程的限制

  2. Exception in thread “main” java.lang.OutOfMemoryError: Java heap space

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

  3. Caused by: java.lang.OutOfMemoryError: Meta space

    这个意思是元数据区的内存占用已经达到XX:MaxMetaspaceSize设置的最大值,排查思路和上面的一致,参数方面可以通过XX:MaxPermSize来进行调整(这里就不说1.8以前的永久代了)。

  4. Exception in thread “main” java.lang.StackOverflowError

    栈内存溢出,表示线程栈需要的内存大于Xss值,同样也是先进行排查,参数方面通过Xss来调整,但调整的太大可能又会引起OOM。

内存问题定位

上述关于OOM和StackOverflow的代码排查方面,我们一般使用JMAPjmap -dump:format=b,file=filename pid来导出dump文件。

Linux——线上故障排查(四)_2021-01-07-14-58-07.png

通过mat(Eclipse Memory Analysis Tools)导入dump文件进行分析。

gc问题

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

除了jstack细细分析dump文件外,我们一般先会看下总体线程,通过pstreee -p pid |wc -l。

Linux——线上故障排查(四)_2021-01-07-15-00-25.png

堆外内存

如果由于使用Netty导致的,那错误日志里可能会出现OutOfDirectMemoryError错误,如果直接是DirectByteBuffer,那会报OutOfMemoryError: Direct buffer memory。

堆外内存溢出往往是和NIO的使用相关

GC

堆内内存泄漏总是和GC异常相伴。不过GC问题不只是和内存问题相关,还有可能引起CPU负载、网络问题等系列并发症,只是相对来说和内存联系紧密些,所以我们在此单独总结一下GC相关问题。

在启动参数中加上-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps来开启GC日志。

youngGC过频繁youngGC频繁一般是短周期小对象较多,先考虑是不是Eden区/新生代设置的太小了,看能否通过调整-Xmn、-XX:SurvivorRatio等参数设置来解决问题。如果参数正常,但是young gc频率还是太高,就需要使用Jmap和MAT对dump文件进行进一步排查了。

youngGC耗时过长耗时过长问题就要看GC日志里耗时耗在哪一块了。以G1日志为例,可以关注Root Scanning、Object Copy、Ref Proc等阶段。Ref Proc耗时长,就要注意引用相关的对象。Root Scanning耗时长,就要注意线程数、跨代引用。Object Copy则需要关注对象生存周期。而且耗时分析它需要横向比较,就是和其他项目或者正常时间段的耗时比较。比如说图中的Root Scanning和正常时间段比增长较多,那就是起的线程太多了。

Linux——线上故障排查(四)_2021-01-07-15-06-09.png

触发fullGCG1中更多的还是mixedGC,但mixedGC可以和youngGC思路一样去排查。触发fullGC了一般都会有问题,G1会退化使用Serial收集器来完成垃圾的清理工作,暂停时长达到秒级别,可以说是半跪了。fullGC的原因可能包括以下这些,以及参数调整方面的一些思路:

  • 并发阶段失败:在并发标记阶段,MixGC之前老年代就被填满了,那么这时候G1就会放弃标记周期。这种情况,可能就需要增加堆大小,或者调整并发标记线程数-XX:ConcGCThreads。
  • 晋升失败:在GC的时候没有足够的内存供存活/晋升对象使用,所以触发了Full GC。这时候可以通过-XX:G1ReservePercent来增加预留内存百分比,减少-XX:InitiatingHeapOccupancyPercent来提前启动标记,-XX:ConcGCThreads来增加标记线程数也是可以的。
  • 大对象分配失败:大对象找不到合适的region空间进行分配,就会进行fullGC,这种情况下可以增大内存或者增大-XX:G1HeapRegionSize。
  • 程序主动执行System.gc():不要随便写就对了。

我们可以在启动参数中配置-XX:HeapDumpPath=/xxx/dump.hprof来dump fullGC相关的文件。

文章目录
  1. 1. 前言
  2. 2. CPU
    1. 2.1. 使用jstack分析cpu问题
    2. 2.2. 频繁GC
    3. 2.3. 频繁上下文切换
  3. 3. 磁盘
  4. 4. 内存
    1. 4.1. 内存不足报错情况
    2. 4.2. 内存问题定位
    3. 4.3. gc问题
    4. 4.4. 堆外内存
  5. 5. GC
|