java线上问题排查技巧

导读:有哪些常见的线上故障?如何快速定位问题?本文详细总结工作中的经验,从服务器、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  发现问题

一般情况下会有监控告警进行提示:

以上文章来源于阿里技术 ,作者小峯

阿里技术

阿里巴巴官方技术号,关于阿里的技术创新均呈现于此。

你可能感兴趣的:(java线上问题排查技巧)