排查Java线上服务故障的方法和实例分析

2024-08-21 05:58

本文主要是介绍排查Java线上服务故障的方法和实例分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

  作为在线系统负责人或者是一个技术专家,你可能刚刚接手一个项目就需要处理紧急故障,或者被要求帮忙处理一些紧急的故障,这个时候的情景是:

  (1)你可能对这个业务仅仅是听说过,而不怎么真正了解;

  (2)你可能没有这个故障的详细信息,比如可能仅仅是有使用方反馈服务中断了10分钟;

  (3)你对代码细节还没有仔细研究过。

  这个时候该怎么解决问题呢?根据以前的经验,工程师们常常倾向于直接登上服务器检查代码,试图立刻修改问题。或者是把某些可能是问题的配置做修改,但并不是100%确认这就是问题的根本原因。但结果往往是在解决问题的同时引入了新的问题,或者是没有找到问题的根本原因,导致用户的再次投诉。

 

正文

  处理和排除故障分为4个必须的步骤:

  (1) 紧急处理

  (2) 添加监控

  (3) 使用JDK性能监控工具

  (4) 分析源代码。从治标不治本,到治标又治本。

 

紧急处理

  紧急处理,顾名思义,是检查和评度当前故障的影响范围,并尽快使服务先恢复起来。其中检查和评估当前故障的影响范围是非常重要的。

  以微博系统举例,一般用户的投诉率为千分之1,如果有超过10起用户投诉,就可能是大面积故障。如果只是负责线上跟踪的QA人员反馈的问题,而没有用户投诉,则可以有较多的时间去处理。

  对于紧急的大面积故障,首先想到的不应该是检查问题。而是需要立刻追查最近线上系统是否有更改,我们的经验是95%的故障都是在新代码上线后的12小时内发生的。此时应该立刻回滚新更改。另外5%的故障大部分是由于业务扩展导致的。互联网业有一个规律,线上系统每半年需要重构一次,否则无法对应业务量的增长。对于这种业务量增长造成的故障,通常可以通过重启服务来紧急处理。

  因此,紧急处理的首选是立刻回滚新更改

 

添加监控

  紧急处理之后,服务已经恢复了,但是问题并没有找到。如果是新代码上线造成的故障,回滚之后,工程师会有各种手段,在测试环境追查问题。而针对系统容量不足造成的故障,需要特别添加监控作为追查问题的重要手段。因为互联网业务请求高峰和低谷差别非常明显,微博业务中的请求高峰往往出现在晚上10点左右,而且不是稳定的出现。要求工程师们每天悲催的坐在电脑前守到晚上10点,却不见得能发现问题,是非常低效的。监控一般用一个简单的脚本就可以搞定,比如http服务监控,Shell脚本代码如下:

  MAX_LATENCY_TIME=5    

  curl -m $MAX_LATENCY_TIME "http://1.2.3.4:8011/...."    

  if [ $? -ne 0 ] ; then  

          sIp=`hostname`  

          errmsg="gexin install latency > "$MAX_LATENCY_TIME"s"  

          // 具体告警的处理  

          echo $errmsg  

          echo send success  

  fi  

 

使用JDK性能监控工具

  刚刚添加的监控开始报警了。登上服务器,该做些什么呢?一般需要做如下动作,

  (1)首先要查看日志,看看有没有Exception。另外日志中常常有对接口调用,缓存使用的监控告警信息。

  (2)看看目前gc的状况如何,使用JDK自带的工具就可以。jstat -gc -h 10 vmid 5000,每5秒打出一次。我遇到过两次线上故障,都是简单的通过jstat就找到了问题。一次是Permanent区分配过小,JVM内存溢出。另一次是发生了过多的Full GC,使得系统停止响应。内存造成的问题通过简单的重启服务就可以使得服务恢复,但重启之后往往很快又出现问题。这个期间你要监控gc,看看期间发生了什么事情。如果是old区增长的过快,就可能是内存泄露。这个时候,你需要看看到底是什么对象占用了你的内存。

  (3)jmap -histo vmid > jmap.log,该命令会打出所有对象,包括占用的byte数和实例个数。分享一个线上jmap实例,

  Jmap.log代码  

  num     #instances         #bytes  class name  

  ---------------------------------------------  

  1:      10540623      668712400  [B  

    2:      10532610      252782640  com.google.protobuf.ByteString  

      3:       4305941      234036872  [Ljava.lang.Object;  

      4:       1066822      170691520  cn.abc.data.protobuf.UserWrap$User  

      5:       3950998      158039920  java.util.TreeMap$Entry  

      6:       3950159      126405088  com.google.protobuf.UnknownFieldSet$Field  

      7:        780773      118677496  cn.abc.data.protobuf.StatusWrap$Status  

      8:       4305047      103321128  java.util.ArrayList  

      9:       4301379      103233096  java.util.Collections$UnmodifiableRandomAccessList  

    10:       3207948      102654336  java.util.HashMap$Entry  

    11:       2571737       82300280  [C  

    12:       2569460       82222720  java.lang.String  

    13:       3952892       63246272  java.lang.Integer  

    14:       1314438       63093024  java.util.TreeMap  

    15:       2533229       60797496  java.lang.Long  

    16:       1065093       51124464  cn.abc.data.protobuf.PostSourceWrap$PostSource  

    17:       1314430       42061760  java.util.Collections$UnmodifiableMap  

    18:        284198       40924512  cn.sina.api.data.protobuf.CommentWrap$Comment  

    19:          4273       34273568  [Ljava.util.HashMap$Entry;  

    20:        459983       33118776  cn.abc.data.protobuf.AbcMessageWrap$AbcMessage  

    21:        458776       22021248  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask  

    22:        458776       22021248  java.util.concurrent.FutureTask$Sync  

    23:       1314416       21030656  com.google.protobuf.UnknownFieldSet  

     24:        459982       11039568  cn.sina.datapush.notifier.core.DispatcherBase$MessageProcessor  

     25:        458776       11010624  java.util.concurrent.Executors$RunnableAdapter  

     26:        458776        7340416  cn.abc.datapush.notifier.core.DispatcherBase$MessageProcessor$1  

     27:         40897        5909152  <constMethodKlass>  

     28:         40897        4917592  <methodKlass>  

     29:          3193        3748688  <constantPoolKlass>  

     30:         62093        3274344  <symbolKlass>  

   排名前几位的都是ByteCharStringInteger之类的,不要灰心,继续往下看,后面会出现一些有趣的对象。第22位发现了45万个FutureTask,很显然这是不正常的。应该是某线程响应过慢,造成待处理任务出现了堆积。查看代码,果然处理线程只有4条,大量的请求得不到响应。通过gc分析,每5秒钟会产生100M左右的对象得不到处理,所以JVM heap很快就被耗尽。将线程数改为36条,问题立刻得到了解决。

 

  (4)检查目前cpu占用情况,top -H,然后按“1”,会看到当前进程中每个线程所占CPU的比例。注意观察前几名,然后jstack -l vmid > jstack.log打出线程堆栈,看看是什么线程占用了CPU。这里需要注意的是,top -H显示的线程id是十进制,而jstack打出的线程堆栈是16进制。看看那些最忙的thread是不是那些真正应该忙的thread,如果是一些黑马线程,则要考虑是否是代码有死循环或者是意外的问题。

 

分析源代码

  分析源代码是最有技术含量的事情,也是比较耗时而且不见得有效果的事情。所以我把源码分析放到解决线上问题的最后一步,因为必须要做到有的放矢。带着问题去分析代码,会比较容易。通过20%代码的修改,就可以解决80%的性能问题。比如上面这个线上问题,肯定是线程处理慢造成的问题。需要针对线程的调用,同步异步等进行分析。

这篇关于排查Java线上服务故障的方法和实例分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092311

相关文章

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Spring Security方法级安全控制@PreAuthorize注解的灵活运用小结

《SpringSecurity方法级安全控制@PreAuthorize注解的灵活运用小结》本文将带着大家讲解@PreAuthorize注解的核心原理、SpEL表达式机制,并通过的示例代码演示如... 目录1. 前言2. @PreAuthorize 注解简介3. @PreAuthorize 核心原理解析拦截与

一文详解JavaScript中的fetch方法

《一文详解JavaScript中的fetch方法》fetch函数是一个用于在JavaScript中执行HTTP请求的现代API,它提供了一种更简洁、更强大的方式来处理网络请求,:本文主要介绍Jav... 目录前言什么是 fetch 方法基本语法简单的 GET 请求示例代码解释发送 POST 请求示例代码解释

Java图片压缩三种高效压缩方案详细解析

《Java图片压缩三种高效压缩方案详细解析》图片压缩通常涉及减少图片的尺寸缩放、调整图片的质量(针对JPEG、PNG等)、使用特定的算法来减少图片的数据量等,:本文主要介绍Java图片压缩三种高效... 目录一、基于OpenCV的智能尺寸压缩技术亮点:适用场景:二、JPEG质量参数压缩关键技术:压缩效果对比

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

Java利用docx4j+Freemarker生成word文档

《Java利用docx4j+Freemarker生成word文档》这篇文章主要为大家详细介绍了Java如何利用docx4j+Freemarker生成word文档,文中的示例代码讲解详细,感兴趣的小伙伴... 目录技术方案maven依赖创建模板文件实现代码技术方案Java 1.8 + docx4j + Fr

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(