Java系统线上生产问题排查一把梭

1 环境

1.1 Dev

可以随意使用任何熟悉的工具排查。只要问题能重现,排查就不会太难,最多就是把程序调试到各种框架源码,所以这也是为何面试都会问源码,不求都看过,但要有思路知道如何去看能解决问题。

1.2 Test

比开发环境少了debug,不过也可使用jvisualvm或Arthas,附加到远程JVM进程。

还有测试环境是允许造数据来模拟我们需要的场景的哦,因此这时遇到问题记得主动沟通测试人员造数据让bug更容易复现。

1.3 Prd

该环境下开发人员的权限最低,所以排查问题时障碍很大:

  • 无法使用调试工具从远程附加进程
  • 快速恢复为先,即使在结婚,也得赶紧修复线上问题。而且生产环境流量大、网络权限严格、调用链路复杂,因此更容易出问题,也是出问题最多的环境。

2 监控

生产环境出现问题时,因为要尽快恢复应用,就不可能保留完整现场用于排查和测试。因此,是否有充足的信息(日志、监控和快照)可以了解历史、还原bug 场景。 最常用的就是 ELK 的日志了,注意:

  • 确保错误、异常信息可被完整记录到文件日志
  • 确保生产上程序的日志级别是INFO以上 记录日志要使用合理的日志优先级,DEBUG用于开发调试、INFO用于重要流程信息、WARN用于需要关注的问题、ERROR用于阻断流程的错误

生产环境需开发配合运维才能做好完备监控:

主机维度

对CPU、内存、磁盘、网络等资源做监控。如果应用部署在虚拟机或k8s集群,那么除了对物理机做基础资源监控外,同样还要对虚拟机或Pod监控。监控层数取决于应用的部署方案,有一层OS就要做一层监控。

网络维度

监控专线带宽、交换机基本情况、网络延迟

所有的中间件和存储都要做好监控

不仅仅是监控进程对CPU、内存、磁盘IO、网络使用的基本指标,更重要的是监控组件内部的一些重要指标。比如最常用的Prometheus,就提供了大量exporter对接各种中间件和存储系统

应用层面

需监控JVM进程的类加载、内存、GC、线程等常见指标(比如使用Micrometer来做应用监控),此外还要确保能够收集、保存应用日志、GC日志

我们再来看看快照。这里的“快照”是指,应用进程在某一时刻的快照。通常情况下,我们会为生产环境的Java应用设置-XX:+HeapDumpOnOutOfMemoryError和-XX:HeapDumpPath=…这2个JVM参数,用于在出现OOM时保留堆快照。这个课程中,我们也多次使用MAT工具来分析堆快照。

分析定位问题的最佳实践

定位问题,首先要定位问题出在哪个层次:Java应用程序自身问题还是外部因素导致。

  • 可以先查看程序是否有异常,异常信息一般比较具体,可以马上定位到大概的问题方向
  • 如果是一些资源消耗型的问题可能不会有异常,我们可以通过指标监控配合显性问题点来定位。

一般问题原因可归类如下:

程序发布后 Bug

回滚,再慢慢通过版本差异分析根因。

外部因素

比如主机、中间件或DB问题。 这种按主机层面问题、中间件或存储(统称组件)的问题分为:

主机层

可使用工具排查:

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

组件

从如下方面排查:

  • 组件所在主机是否有问题
  • 组件进程基本情况,观察各种监控指标
  • 组件的日志输出,特别是错误日志
  • 进入组件控制台,使用一些命令查看其运作情况。

系统资源不够造成系统假死

通常先通过重启和扩容解决问题,之后再分析,最好能留个快照。

系统资源不够,一般可能:

CPU使用高

若现场还在,具体分析流程:

  • 在服务器执行top -Hp pid 查看进程中哪个线程CPU使用高
  • 输入大写的P将线程按照 CPU 使用率排序,并把明显占用CPU的线程ID转换为16进制
  • 在jstack命令输出的线程栈中搜索这个线程ID,定位出问题的线程当时的调用栈

若无法直接在服务器执行top,可采样定位:间隔固定时间运行一次jstack,采样几次后,对比采样得出哪些线程始终处于运行状态,找出问题线程。

若现场没了,可排除法分析。CPU使用高,一般是由下面的因素引起的:

  • 突发压力 可通过应用之前的负载均衡的流量或日志量确认,诸如Nginx等反向代理都会记录URL,可依靠代理的Access Log进行细化定位,也可通过监控观察JVM线程数的情况。压力问题导致CPU使用高的情况下,如果程序的各资源使用没有明显不正常,之后可以通过压测+Profiler(jvisualvm就有这个功能)进一步定位热点方法;如果资源使用不正常,比如产生了几千个线程,就需要考虑调参
  • GC 可通过JVM监控GC相关指标、GC Log确认。如果确认是GC压力,那么内存使用也很可能会不正常,需要按照内存问题分析流程做进步分析。
  • 死循环或不正常处理流程 可以结合应用日志分析。一般情况下,应用执行过程中都会产生一些日志,可以重点关注日志量异常部分。

内存泄露或OOM

最简单的就是堆转储后使用MAT分析。堆转储,包含了堆现场全貌和线程栈信息,一般观察支配树图、直方图就可以马上看到占用大量内存的对象,可以快速定位到内存相关问题 Java进程对内存的使用不仅仅是堆区,还包括线程使用的内存(线程个数*每一个线程的线程栈)和元数据区。每一个内存区都可能产生OOM,可以结合监控观察线程数、已加载类数量等指标分析 注意看JVM参数的设置是否有明显不合理的,限制了资源。

IO问题

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

网络

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

迷茫时的最佳实践

偶尔可能分析和定位难题,会迷失自我。如果你也这样,可参考如下经验

cause or result?

比如业务执行的很慢,而且线程数增多,那就可能是:

  • 代码逻辑有问题、依赖的外部服务慢 使得自己的业务逻辑执行缓慢,在访问量不变情况下,就需要更多线程处理。比如,10 TPS的并发原先一次请求1s即可完成,10个线程可支撑;现在执行完成需要10s,就需100个线程
  • 请求量增大 使得线程数增多,应用本身CPU不足,上下文切换问题导致处理变慢

这时就需要多结合监控指标和各服务的入口流量,分析慢是cause or result。

探求规律

如果没头绪,那就试试总结规律吧! 比如

  • 有一堆服务器做负载均衡,出问题时可分析监控和日志看请求是否是均匀分布的,可能问题都集中在某个机器节点上
  • 应用日志一般会记录线程名称,出问题时可分析日志是否集中在某类线程
  • 若发现应用开启大量TCP连接,通过netstat可分析出主要集中连接到哪个服务

探求到了规律,就很容易突破了。

调用拓扑

比如看到Nginx返回502,一般可认为是下游服务的问题导致网关无法完成请求转发。 对于下游服务,不能想当然就认为是我们的Java程序,比如在拓扑上可能Nginx代理的是Kubernetes的Traefik Ingress,链路是Nginx->Traefik->应用,如果一味排查Java程序的健康,则始终找不到根因。

有时虽然使用了Feign进行服务调用,出现连接超时也不一定就是服务端问题,有可能是客户端通过URL调用服务端,并非通过Eureka的服务发现实现的客户端负载均衡。即客户端连接的是Nginx代理而非直接连接应用,客户端连接服务出现的超时,其实是Nginx代理宕机所致。

资源限制

观察各种监控指标,如果发现曲线慢慢上升然后稳定在一个水平线,一般就是资源达到瓶颈。

观察网络带宽曲线时,如果带宽上升到120MB左右不动了,很可能就是打满了1GB的网卡或传输带宽 观察到数据库活跃连接数上升到10个不动了,很可能是连接池打满了

观察监控一旦看到任何这样曲线,都要引起重视。

连锁反应

CPU、内存、IO和网络相辅相成,一个资源出现瓶颈,很可能同时引起其他资源连锁反应。

内存泄露后对象无法回收会造成大量Full GC,CPU会大量消耗在GC从而引起CPU使用增加

经常会把数据缓存在内存队列进行异步IO,网络或磁盘出现问题时,就很可能会引起内存暴涨。

所以出问题时,要综合考虑避免误判

客户端or服务端or传输问题?

比如MySQL访问慢了,可能:

  • 客户端原因,连接池不够导致连接获取慢、GC停顿、CPU占满
  • 传输过程问题 包括光纤可能被挖断了呀、防火墙、路由表等设置有问题
  • 真的服务端背锅了

这都需要逐一排查区分。

服务端慢一般可以看到MySQL出慢日志,传输慢一般可以通过ping来简单定位,排除了这两个可能,并且仅仅是部分客户端出现访问慢的情况,就需要怀疑是客户端本身的问题。对于第三方系统、服务或存储访问出现慢的情况,不能完全假设是服务端的问题。

第七,快照类工具和趋势类工具需要结合使用。比如,jstat、top、各种监控曲线是趋势类工具,可以让我们观察各个指标的变化情况,定位大概的问题点;而jstack和分析堆快照的MAT是快照类工具,用于详细分析某一时刻应用程序某一个点的细节。

一般情况下,我们会先使用趋势类工具来总结规律,再使用快照类工具来分析问题。如果反过来可能就会误判,因为快照类工具反映的只是一个瞬间程序的情况,不能仅仅通过分析单一快照得出结论,如果缺少趋势类工具的帮助,那至少也要提取多个快照来对比。

第八,不要轻易怀疑监控。我曾看过一个空难事故的分析,飞行员在空中发现仪表显示飞机所有油箱都处于缺油的状态,他第一时间的怀疑是油表出现故障了,始终不愿意相信是真的缺油,结果飞行不久后引擎就断油熄火了。同样地,在应用出现问题时,我们会查看各种监控系统,但有些时候我们宁愿相信自己的经验,也不相信监控图表的显示。这可能会导致我们完全朝着错误的方向来排查问题。

如果你真的怀疑是监控系统有问题,可以看一下这套监控系统对于不出问题的应用显示是否正常,如果正常那就应该相信监控而不是自己的经验。

第九,如果因为监控缺失等原因无法定位到根因的话,相同问题就有再出现的风险,需要做好三项工作:

做好日志、监控和快照补漏工作,下次遇到问题时可以定位根因; 针对问题的症状做好实时报警,确保出现问题后可以第一时间发现; 考虑做一套热备的方案,出现问题后可以第一时间切换到热备系统快速解决问题,同时又可以保留老系统的现场。

总结

分析问题必须讲理

靠猜是猜不出来的,需要提前做好基础监控的建设。监控的话,需要在基础运维层、应用层、业务层等多个层次进行。定位问题的时候,我们同样需要参照多个监控层的指标表现综合分析。

定位问题要先对原因进行大致分类

比如是内部问题还是外部问题、CPU相关问题还是内存相关问题、仅仅是A接口的问题还是整个应用的问题,然后再去进一步细化探索,一定是从大到小来思考问题;在追查问题遇到瓶颈的时候,我们可以先退出细节,再从大的方面捋一下涉及的点,再重新来看问题。

经验很重要

遇到重大问题的时候,往往也需要根据直觉来第一时间找到最有可能的点,这里甚至有运气成分。我还和你分享了我的九条经验,建议你在平时解决问题的时候多思考、多总结,提炼出更多自己分析问题的套路和拿手工具。

定位到问题原因后,要做好复盘回溯。每次故障的解决都是宝贵经验,复盘不止是记录问题,更是为了架构优化。 复盘可重点关注如下:

  • 记录完整的时间线、处理措施、上报流程等信息
  • 分析问题的根本原因
  • 给出短、中、长期改进方案,包括但不限于代码改动、SOP、流程,并记录跟踪每一个方案进行闭环
  • 定期组织团队回顾过去的故障

原文地址:https://cloud.tencent.com/developer/article/2181198

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 连接 连接池产生原因 连接池实现原理 小结 TEMPERANCE:Eat not to dullness;drink not to elevation.节制
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 一个优秀的工程师和一个普通的工程师的区别,不是满天飞的架构图,他的功底体现在所写的每一行代码上。-- 毕玄 1. 命名风格 【书摘】类名用 UpperCamelC
今天犯了个错:“接口变动,伤筋动骨,除非你确定只有你一个人在用”。哪怕只是throw了一个新的Exception。哈哈,这是我犯的错误。一、接口和抽象类类,即一个对象。先抽象类,就是抽象出类的基础部分,即抽象基类(抽象类)。官方定义让人费解,但是记忆方法是也不错的 —包含抽象方法的类叫做抽象类。接口
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket一、引子文件,作为常见的数据源。关于操作文件的字节流就是 —FileInputStream&FileOutputStream。
作者:泥沙砖瓦浆木匠网站:http://blog.csdn.net/jeffli1993个人签名:打算起手不凡写出鸿篇巨作的人,往往坚持不了完成第一章节。交流QQ群:【编程之美 365234583】http://qm.qq.com/cgi-bin/qm/qr?k=FhFAoaWwjP29_Aonqz
本文目录 线程与多线程 线程的运行与创建 线程的状态 1 线程与多线程 线程是什么? 线程(Thread)是一个对象(Object)。用来干什么?Java 线程(也称 JVM 线程)是 Java 进程内允许多个同时进行的任务。该进程内并发的任务成为线程(Thread),一个进程里至少一个线程。 Ja
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket在面向对象编程中,编程人员应该在意“资源”。比如?1String hello = "hello"; 在代码中,我们
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 这是泥瓦匠的第103篇原创 《程序兵法:Java String 源码的排序算法(一)》 文章工程:* JDK 1.8* 工程名:algorithm-core-le
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 一、父子类变量名相同会咋样? 有个小故事,今天群里面有个人问下面如图输出什么? 我回答:60。但这是错的,答案结果是 40 。我知错能改,然后说了下父子类变
作者:泥瓦匠 出处:https://www.bysocket.com/2021-10-26/mac-create-files-from-the-root-directory.html Mac 操作系统挺适合开发者进行写代码,最近碰到了一个问题,问题是如何在 macOS 根目录创建文件夹。不同的 ma
作者:李强强上一篇,泥瓦匠基础地讲了下Java I/O : Bit Operation 位运算。这一讲,泥瓦匠带你走进Java中的进制详解。一、引子在Java世界里,99%的工作都是处理这高层。那么二进制,字节码这些会在哪里用到呢?自问自答:在跨平台的时候,就凸显神功了。比如说文件读写,数据通信,还
1 线程中断 1.1 什么是线程中断? 线程中断是线程的标志位属性。而不是真正终止线程,和线程的状态无关。线程中断过程表示一个运行中的线程,通过其他线程调用了该线程的 方法,使得该线程中断标志位属性改变。 深入思考下,线程中断不是去中断了线程,恰恰是用来通知该线程应该被中断了。具体是一个标志位属性,
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want需求 项目在设计表的时候,要处理并发多的一些数据,类似订单号不能重复,要保持唯一。原本以为来个时间戳,精确到毫秒应该不错了。后来觉得是错了,测试环境下很多一
纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 纯技术交流群 每日推荐 - 技术干货推送 跟着泥瓦匠,一起问答交流 扫一扫,我邀请你入群 加微信:bysocket01
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocketReprint it anywhere u want.文章Points:1、介绍RESTful架构风格2、Spring配置CXF3、三层初设计,实现WebService接口层4、撰写HTTPClient 客户
Writer :BYSocket(泥沙砖瓦浆木匠)什么是回调?今天傻傻地截了张图问了下,然后被陈大牛回答道“就一个回调…”。此时千万个草泥马飞奔而过(逃哈哈,看着源码,享受着这种回调在代码上的作用,真是美哉。不妨总结总结。一、什么是回调回调,回调。要先有调用,才有调用者和被调用者之间的回调。所以在百
Writer :BYSocket(泥沙砖瓦浆木匠)一、什么大小端?大小端在计算机业界,Endian表示数据在存储器中的存放顺序。百度百科如下叙述之:大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加
What is a programming language? Before introducing compilation and decompilation, let's briefly introduce the Programming Language. Programming la
Writer :BYSocket(泥沙砖瓦浆木匠)微 博:BYSocket豆 瓣:BYSocketFaceBook:BYSocketTwitter :BYSocket泥瓦匠喜欢Java,文章总是扯扯Java。 I/O 基础,就是二进制,也就是Bit。一、Bit与二进制什么是Bit(位)呢?位是CPU
Writer:BYSocket(泥沙砖瓦浆木匠)微博:BYSocket豆瓣:BYSocket一、前言 泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标:专注很重要。专注Java 基础 + H5(学习) 其他操作系统,算法,数据结构当成课外书博览。有时候,就是那样你越是专注方面越