一整套线上故障排查技巧,爱了( 二 )


磁盘
磁盘问题和 CPU 一样是属于比较基础的 。 首先是磁盘空间方面 , 我们直接使用 df -hl 来查看文件系统状态:
一整套线上故障排查技巧,爱了文章插图
更多时候 , 磁盘问题还是性能上的问题 。 我们可以通过 iostatiostat -d -k -x 来进行分析:
一整套线上故障排查技巧,爱了文章插图
最后一列 %util 可以看到每块磁盘写入的程度 , 而 rrqpm/s 以及 wrqm/s 分别表示读写速度 , 一般就能帮助定位到具体哪块磁盘出现问题了 。
另外我们还需要知道是哪个进程在进行读写 , 一般来说开发自己心里有数 , 或者用 iotop 命令来进行定位文件读写的来源 。
一整套线上故障排查技巧,爱了文章插图
不过这边拿到的是 tid , 我们要转换成 pid , 可以通过 readlink 来找到 pidreadlink -f /proc/*/task/tid/../.. 。
一整套线上故障排查技巧,爱了文章插图
找到 pid 之后就可以看这个进程具体的读写情况 cat /proc/pid/io:
一整套线上故障排查技巧,爱了文章插图
我们还可以通过 lsof 命令来确定具体的文件读写情况 lsof -p pid:
一整套线上故障排查技巧,爱了文章插图
内存
内存问题排查起来相对比 CPU 麻烦一些 , 场景也比较多 。 主要包括 OOM、GC 问题和堆外内存 。
一般来讲 , 我们会先用 free 命令先来检查一发内存的各种情况:
一整套线上故障排查技巧,爱了文章插图
堆内内存
内存问题大多还都是堆内内存问题 。 表象上主要分为 OOM 和 Stack Overflow 。
①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 来进行调整(这里就不说 1.8 以前的永久代了) 。
②Stack Overflow
栈内存溢出 , 这个大家见到也比较多 。
Exception in thread "main" java.lang.StackOverflowError
表示线程栈需要的内存大于 Xss 值 , 同样也是先进行排查 , 参数方面通过Xss来调整 , 但调整的太大可能又会引起 OOM 。
③使用 JMAP 定位代码内存泄漏
上述关于 OOM 和 Stack Overflow 的代码排查方面 , 我们一般使用 JMAPjmap -dump:format=b,file=filename pid 来导出 dump 文件:
一整套线上故障排查技巧,爱了文章插图
通过 mat(Eclipse Memory Analysis Tools)导入 dump 文件进行分析 , 内存泄漏问题一般我们直接选 Leak Suspects 即可 , mat 给出了内存泄漏的建议 。
另外也可以选择 Top Consumers 来查看最大对象报告 。 和线程相关的问题可以选择 thread overview 进行分析 。
除此之外就是选择 Histogram 类概览来自己慢慢分析 , 大家可以搜搜 mat 的相关教程 。
一整套线上故障排查技巧,爱了文章插图
日常开发中 , 代码产生内存泄漏是比较常见的事 , 并且比较隐蔽 , 需要开发者更加关注细节 。
比如说每次请求都 new 对象 , 导致大量重复创建对象;进行文件流操作但未正确关闭;手动不当触发 GC;ByteBuffer 缓存分配不合理等都会造成代码 OOM 。
另一方面 , 我们可以在启动参数中指定 -XX:+HeapDumpOnOutOfMemoryError 来保存 OOM 时的 dump 文件 。