定位问题-排错

不同的环境排查问题的方式

开发环境:开发工具单步调试。

测试环境:jdk自带jvisualvm或阿里的Arthas,附加到远程的JVM进程排查问题;

压测环境:造数据、造压力模拟需要的场景,遇到偶发问题,尝试造一些场景让问题更容易出现,方便测试;

生产环境:权限管控严格,一般不允许调试工具从远程附加进程;另一方面,生产环境出现问题要求以恢复为先,难以留出充足的时间去慢慢排查问题。因为生产环境流量真实、访问量大、网络权限管控严格、环境复杂,更容易出问题,也是出问题最多的环境。

生产问题排查比较依赖监控

日志 

确保错误、异常信息可以被完成地记录到日志文件中(可以使用注解的方式,在调用第三方接口时加上打日志的注解);

确保生产上程序的日志级别是INFO用于重要流程信息、WARN用于需要关注的问题、ERROR用于阻断流程的错误;

监控 

主机层面:对cpu、内存、磁盘、网络等资源做监控。部署到Kubernetes集群需要对pod做监控,监控层数取决于应用的部署方案,有一层OS就做一层监控。

网络层面: 需要监控专线带宽、交换机基本情况、网络延迟。

监控中间件和存储:如使用监控工具Prometheus,提供了大量exporter来对接各种中间件和存储系统。

应用层面:监控JVM进程的类加载、内存、GC、线程等常见指标(如使用Micrometer应用监控),能确保收集保存应用日志和GC日志。

快照:通常情况下,我们会为生产环境的 Java 应用设置 -XX:+HeapDumpOnOutOfMemoryError 和 -XX:HeapDumpPath=…这 2 个 JVM 参数,用于在出现 OOM 时保留堆快照。(使用MAT工具分析堆快照)

分析定位问题套路

定位问题:首先要定位问题出现在哪个层次上。

比如,是Java应用程序自身的问题还是外部因素导致的问题。配合指标监控显性问题来定位;一般程序问题从三个方面看

1. 程序发布后的Bug,回滚后可以立即解决。这类问题排查,可以回滚后慢慢分析版本差异。

2. 外部因素,如主机、中间件或数据库的问题。这类问题的排查方式,按照主机层面的问题、中间件或存储(j统计组建)的问题分位两类。

主机层面问题,可以使用工具排查:

CPU相关问题,可以使用 top、vmstat、pidstat、ps 等工具排查;

内存相关问题,可以使用 free、top、ps、vmstat、cachestat、sar 等工具排查;

IO 相关问题,可以使用 lsof、iostat、pidstat、sar、iotop、df、du 等工具排查;

网络相关问题,可以使用 ifconfig、ip、nslookup、dig、ping、tcpdump、iptables 等工具排查。

组件的问题,可以从以下几个方面排查:

排查组件所在主机是否有问题;

排查组件进程基本情况,观察各种监控指标;

查看组件的日志输出,特别是错误日志;

进入组件控制台,使用一些命令查看其运作情况。

3. 因为系统资源不够造成系统假死的问题,通常需要先通过重启扩容解决问题,之后进行分析,最好能留一个节点作为现场。系统资源不够,一般体现在cpu使用高、内存泄漏、oom问题、io问题、网络相关问题四个方面。

对于cpu高问题,如果现场还在,具体分析流程是:

1. 首先,在Linux服务器上运行top -Hp pid命令,查看进程中哪个线程cpu使用高;

2. 然后,输入大写的P将线程按照cpu使用率排序,并把明显占用cpu的线程ip转换为16进制;

3. 最后,在jstack命令输入的线程栈中搜索这个线程ID,定位出问题的线程当时调用的栈;

如果没有条件直接在服务器上运行 top 命令的话,我们可以用采样的方式定位问题:间隔固定秒数(比如 10 秒)运行一次 jstack 命令,采样几次后,对比采样得出哪些线程始终处于运行状态,分析出问题的线程。

排除法来分析

cpu使用高,一般由下面因素引起的:

突发压力:这类问题,通过应用之前的负载均衡的流量或日志量来确认,诸如Nginx等反向代理都会记录URL,依赖代理的Access Log进行细化定位,也可以通过监控JVM线程数的情况。压力问题导致CPU使用高的情况下,如果程序的哥哥资源使用没有明显不正常,可以通过压测+Profilter(jvisualvm)进一步定位热点方法;如果系统使用不正常,产生了几千个线程,需要考虑调参。

GC:这种情况通过JVM监控GC相关指标、GC Log进行确认。如果确认是GC压力,那么内存使用也会不正常,需要按照内存问题分析流程做进一步分析。

程序中死循环逻辑或不正常的处理流程:这类问题,可以结合应用日志分析,一般情况下,应用执行过程中都会产生一些日志,重点关注日志量异常部分。

内存泄露或 OOM 的问题:最简单的分析方式,就是堆转储后使用 MAT 分析。需要注意的是,Java 进程对内存的使用不仅仅是堆区,还包括线程使用的内存(线程个数 * 每一个线程的线程栈)和元数据区。每一个内存区都可能产生 OOM,可以结合监控观察线程数、已加载类数量等指标分析。另外,我们需要注意看一下,JVM 参数的设置是否有明显不合理的地方,限制了资源使用。

IO 相关的问题:除非是代码问题引起的资源不释放等问题,否则通常都不是由 Java 进程内部因素引发的。

网络相关的问题:一般也是由外部因素引起的。对于连通性问题,结合异常信息通常比较容易定位;对于性能或瞬断问题,可以先尝试使用 ping 等工具简单判断,如果不行再使用 tcpdump 或 Wireshark 来分析。

原文链接:https://time.geekbang.org/column/intro/100047701

posted @ 2022-08-05 08:59  白玉神驹  阅读(43)  评论(0编辑  收藏  举报