导读:有哪些常见的线上故障?如何快速定位问题?本文详细总结工作中的经验,从服务器、Java应用、数据库、Redis、网络和业务六个层面分享线上故障排查的思路和技巧。较长,同学们可收藏后再看。
前言
线上定位问题时,主要靠监控和日志。一旦超出监控的范围,则排查思路很重要,按照流程化的思路来定位问题,能够让我们在定位问题时从容、淡定,快速的定位到线上的问题。
线上问题定位思维导图
一 服务器层面
1.1 磁盘
1.1.1 问题现象
当磁盘容量不足的时候,应用时常会抛出如下的异常信息:
java.io.IOException: 磁盘空间不足
或是类似如下告警信息:
1.1.2 排查思路
1.1.2.1 利用 df 查询磁盘状态
利用以下指令获取磁盘状态:
df -h
结果是:
可知 / 路径下占用量最大。
1.1.2.2 利用 du 查看文件夹大小
利用以下指令获取目录下文件夹大小:
du -sh *
结果是:
可知root文件夹占用空间最大,然后层层递推找到对应的最大的一个或数个文件夹。
1.1.2.3 利用 ls 查看文件大小
利用以下指令获取目录下文件夹大小:
ls -lh
结果是:
可以找到最大的文件是日志文件,然后使用rm指令进行移除以释放磁盘。
1.1.3 相关命令
1.1.3.1 df
主要是用于显示目前在 Linux 系统上的文件系统磁盘使用情况统计。
(1)常用参数
启动参数:
(2)结果参数
1.1.3.2 du
主要是为了显示目录或文件的大小。
(1)常用参数
启动参数:
(2)结果参数
1.1.3.3 ls
主要是用于显示指定工作目录下的内容的信息。
(1)常用参数
启动参数:
(2)结果参数
1.2 CPU过高
1.2.1 问题现象
当CPU过高的时候,接口性能会快速下降,同时监控也会开始报警。
1.2.2 排查思路
1.2.2.1 利用 top 查询CPU使用率最高的进程
利用以下指令获取系统CPU使用率信息:
top
结果是:
从而可以得知pid为14201的进程使用CPU最高。
1.2.3 相关命令
1.2.3.1 top
(1)常用参数
启动参数:
top进程内指令参数:
(2)结果参数
二 应用层面
2.1 Tomcat假死案例分析
2.1.1 发现问题
监控平台发现某个Tomcat节点已经无法采集到数据,连上服务器查看服务器进程还在,netstat -anop|grep 8001端口也有监听,查看日志打印时断时续。
2.2.2 查询日志
查看NG日志,发现有数据进入到当前服务器(有8001和8002两个Tomcat),NG显示8002节点访问正常,8001节点有404错误打印,说明Tomcat已经处于假死状态,这个Tomcat已经不能正常工作了。
过滤Tomcat节点的日志,发现有OOM的异常,但是重启后,有时候Tomcat挂掉后,又不会打印如下OOM的异常:
TopicNewController.getTopicSoftList() error="Java heap space From class java.lang.OutOfMemoryError"appstore_apitomcat
2.2.3 获取内存快照
在一次OOM发生后立刻抓取内存快照,需要执行命令的用户与JAVA进程启动用户是同一个,否则会有异常:
/data/program/jdk/bin/jmap -dump:live,format=b,file=/home/www/jmaplogs/jmap-8001-2.bin18760ps -ef|grepstore.cn.xml|grep-vgrep|awk'{print $2}'|xargs /data/program/jdk-1.8.0_11/bin/jmap -dump:live,format=b,file=api.bin
内存dump文件比较大,有1.4G,先压缩,然后拉取到本地用7ZIP解压。
linux压缩dump为.tgz。
在windows下用7zip需要经过2步解压:
.bin.tgz---.bin.tar--.bin
2.2.4 分析内存快照文件
使用Memory Analyzer解析dump文件,发现有很明显的内存泄漏提示。
点击查看详情,发现定位到了代码的具体某行,一目了然:
查看shallow heap与retained heap能发现生成了大量的Object(810325个对象),后面分析代码发现是上报softItem对象超过300多万个对象,在循环的时候,所有的数据全部保存在某个方法中无法释放,导致内存堆积到1.5G,从而超过了JVM分配的最大数,从而出现OOM。
java.lang.Object[810325] @ 0xb0e971e0
2.2.5 相关知识
2.2.5.1 JVM内存
2.2.5.2 内存分配的流程
如果通过逃逸分析,则会先在TLAB分配,如果不满足条件才在Eden上分配。
2.2.4.3 GC
(1)GC触发的场景
(2)GC Roots
GC Roots有4种对象:
虚拟机栈(栈桢中的本地变量表)中的引用的对象,就是平时所指的java对象,存放在堆中。
方法区中的类静态属性引用的对象,一般指被static修饰引用的对象,加载类的时候就加载到内存中。
方法区中的常量引用的对象。
本地方法栈中JNI(native方法)引用的对象。
(3)GC算法
串行只使用单条GC线程进行处理,而并行则使用多条。
多核情况下,并行一般更有执行效率,但是单核情况下,并行未必比串行更有效率。
STW会暂停所有应用线程的执行,等待GC线程完成后再继续执行应用线程,从而会导致短时间内应用无响应。
Concurrent会导致GC线程和应用线程并发执行,因此应用线程和GC线程互相抢用CPU,从而会导致出现浮动垃圾,同时GC时间不可控。
(4)新生代使用的GC算法
新生代算法都是基于Coping的,速度快。
Parallel Scavenge:吞吐量优先。
吞吐量=运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)
(5)老年代使用的GC算法
Parallel Compacting
Concurrent Mark-Sweep(CMS)
(6)垃圾收集器总结
(7)实际场景中算法使用的组合
(8)GC日志格式
(a)监控内存的OOM场景
不要在线上使用jmap手动抓取内存快照,其一系统OOM时手工触发已经来不及,另外在生成dump文件时会占用系统内存资源,导致系统崩溃。只需要在JVM启动参数中提取设置如下参数,一旦OOM触发会自动生成对应的文件,用MAT分析即可。
# 内存OOM时,自动生成dump文件 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/
如果Young GC比较频繁,5S内有打印一条,或者有Old GC的打印,代表内存设置过小或者有内存泄漏,此时需要抓取内存快照进行分享。
(b)Young Gc日志
2020-09-23T01:45:05.487+0800: 126221.918: [GC (Allocation Failure) 2020-09-23T01:45:05.487+0800: 126221.918: [ParNew: 1750755K->2896K(1922432K), 0.0409026 secs] 1867906K->120367K(4019584K), 0.0412358 secs] [Times: user=0.13 sys=0.01, real=0.04 secs]
(c)Old GC日志
2020-10-27T20:27:57.733+0800: 639877.297: [Full GC (Heap Inspection Initiated GC) 2020-10-27T20:27:57.733+0800: 639877.297: [CMS: 165992K->120406K(524288K), 0.7776748 secs] 329034K->120406K(1004928K), [Metaspace: 178787K->178787K(1216512K)], 0.7787158 secs] [Times: user=0.71 sys=0.00, real=0.78 secs]
2.2 应用CPU过高
2.2.1 发现问题
一般情况下会有监控告警进行提示:
以上文章来源于阿里技术 ,作者小峯
阿里技术
阿里巴巴官方技术号,关于阿里的技术创新均呈现于此。