线上问题排查思路

2023-10-16 15:33:41 浏览数 (1)

若用户反馈线上服务请求无响应,可以按照以下步骤进行排查。

一、确认服务器内存使用情况

执行free命令,看看服务器内存是否正常。

代码语言:javascript复制
 total        used        free      shared  buff/cache   available
 Mem:       16256764     7583240     2177924     2901216     6495600     5437168
 Swap:       2097148        1280     2095868

看起来服务器内存是正常的。

二、确认服务器磁盘使用情况

执行df -h命令,查看磁盘使用情况。

代码语言:javascript复制
文件系统                  容量    已用  可用  已用%  挂载点
xxxxxxxx                 7.8G     0   7.8G    5%   /xx
……

磁盘空间看起来也是充足的。

三、查看哪个进程占用内存多

输入top命令,然后按 shift p,最前面的就是占用内存最多的。

代码语言:javascript复制
 PID     USER     PR  NI    VIRT     RES    SHR S     %CPU %MEM   TIME       COMMAND
32297   xxxxxx    20   0    109.7g   4.7g   4.0g S   46.2 30.2    160554:47    java

这里可以获取到占用内存最多的pid。

四、查看线程的堆栈信息

执行jstack <pid>,会显示线程的状态。

代码语言:javascript复制
Full thread dump OpenJDK 64-Bit Server VM (17 35-2724 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007f24080015b0, length=41, elements={
0x00007f266c0899e0, 0x00007f266c08b050, 0x00007f266c091d60, 0x00007f266c093280,
0x00007f266c0948a0, 0x00007f266c0964a0, 0x00007f266c097c00, 0x00007f266c0a12a0,
0x00007f266c0befe0, 0x00007f266c0fa7d0, 0x00007f266c23c6b0, 0x00007f266c26dab0,
0x00007f266c425430, 0x00007f266c5ce320, 0x00007f266c6a3ca0, 0x00007f266c6e9790,
0x00007f266c9297f0, 0x00007f266c92d740, 0x00007f266c95d4a0, 0x00007f266c027640,
0x00007f23b8005600, 0x00007f23dc55f2c0, 0x00007f23dc5705c0, 0x00007f23bc0b8bc0,
0x00007f23bc15ebf0, 0x00007f23bc1e0cd0, 0x00007f23b800b850, 0x00007f23b800c2e0,
0x00007f23b800d370, 0x00007f23b800e9d0, 0x00007f23b800fbd0, 0x00007f23b8010ee0,
0x00007f23b8012220, 0x00007f23c4439b80, 0x00007f23c4006500, 0x00007f23c46ae980,
0x00007f23544eeb00, 0x00007f237c406d00, 0x00007f23a829ba30, 0x00007f23c46b2560,
0x00007f2408000a90
}

"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=1463269.24ms elapsed=23238405.12s tid=0x00007f266c0899e0 nid=0x7e38 waiting on condition  [0x00007f26542be000]
   java.lang.Thread.State: RUNNABLE
        at java.lang.ref.Reference.waitForReferencePendingList(java.base@17/Native Method)
        at java.lang.ref.Reference.processPendingReferences(java.base@17/Reference.java:253)
        at java.lang.ref.Reference$ReferenceHandler.run(java.base@17/Reference.java:215)

如果有死锁,就会有下面这种:

代码语言:javascript复制
java.lang.Thread.State: BLOCKED
     at xxxxxx1
     - waiting to lock <0xxxxxx>
     - locked <1xxxxx>
java.lang.Thread.State: BLOCKED
     at xxxxxx2
     - waiting to lock <1xxxxxx>
     - locked <0xxxxx>
五、查看堆内存占用情况

执行jmap -heap <pid>命令,可以看到堆内存的使用情况。

代码语言:javascript复制
Attaching to process ID 5064, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 536870912 (512.0MB)
   NewSize                  = 268435456 (256.0MB)
   MaxNewSize               = 268435456 (256.0MB)
   OldSize                  = 268435456 (256.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 134217728 (128.0MB)
   CompressedClassSpaceSize = 260046848 (248.0MB)
   MaxMetaspaceSize         = 268435456 (256.0MB)
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 241172480 (230.0MB)
   used     = 94437072 (90.06221008300781MB)
   free     = 146735408 (139.9377899169922MB)
   39.15748264478601% used
From Space:
   capacity = 13107200 (12.5MB)
   used     = 3045992 (2.9048843383789062MB)
   free     = 10061208 (9.595115661621094MB)
   23.23907470703125% used
To Space:
   capacity = 12582912 (12.0MB)
   used     = 0 (0.0MB)
   free     = 12582912 (12.0MB)
   0.0% used
PS Old Generation
   capacity = 268435456 (256.0MB)
   used     = 84914376 (80.98065948486328MB)
   free     = 183521080 (175.01934051513672MB)
   31.63307011127472% used

46153 interned Strings occupying 5019920 bytes.

这里可以看到伊甸园区、from区、to区和老年代的内存占用情况,如果老年代99.99%了,那就是堆内存溢出了。

六、查看堆内存中内存占用前10的对象信息

jmap -histo:live <pid> | head -n 10 执行这个命令,可以看到内存占用前10的对象信息。

代码语言:javascript复制
num     #instances         #bytes  class name
----------------------------------------------
   1:        165329       18150792  [C
   2:        163258        3918192  java.lang.String
   3:         40481        3562328  java.lang.reflect.Method
   4:         28014        2844936  [Ljava.lang.Object;
   5:         67703        2166496  java.util.concurrent.ConcurrentHashMap$Node
   6:          7919        2106384  [B
   7:         17131        1934896  java.lang.Class

如果这里看到有自己写的类对象,那可能就可以找到问题了。

七、分析内存溢出问题

确定了是哪一个节点有问题,那么先把节点的流量切走。 如果第六步没分析出来是什么导致内存溢出,可以按如下步骤排查。

1. 导出dump文件 jmap -dump:format=b,live,file=<fileName>.hprof <pid> 执行该命令,可以导出名为fileName.hprof的dump文件

2. 分析dump文件 这里介绍使用mat工具分析dump文件。

  • 先点击mat工具的 window ---> preferences ---> memory Analyzer,把 keep unreachable objects 勾选上,勾上了会保留不可达对象;
  • 点击 file ---> open heap dump,选择刚才的dump文件,等待几分钟,mat工具会生成一个默认的报告;
  • 默认报告里会列出problems,点击details就可以看到问题详情,一般会列出有问题的对象;
  • 选择有问题的对象,右键Merge Shortest Paths to GC Roots ---> exclude weak references
  • 然后再Java Basics ---> Thread Details,这样就可以看到线程详情,线程详情中就会有错误信息,可以定位到在代码的哪一行报错了;

如果默认报告按照上面的方式定位不到具体代码,那可以尝试以下步骤:

  • 在overview页点击histogram,然后按照retained heap排序;
  • 然后选择默认排在前面的对象,右键merge shortest path to GC Roots
  • 然后选择线程,Java Basics ---> Thread Details,一个个地看详情详情,一般看前几个就可以定位到问题了。

0 人点赞