排查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>
排名前几位的都是Byte,Char,String,Integer之类的,不要灰心,继续往下看,后面会出现一些有趣的对象。第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线上服务故障的方法和实例分析的更多相关文章
- 【转】java线上程序排错经验2 - 线程堆栈分析
		前言 在线上的程序中,我们可能经常会碰到程序卡死或者执行很慢的情况,这时候我们希望知道是代码哪里的问题,我们或许迫切希望得到代码运行到哪里了,是哪一步很慢,是否是进入了死循环,或者是否哪一段代码有问题 ... 
- Java线上应用故障排查之二:高内存占用
		搞Java开发的,经常会碰到下面两种异常: 1.java.lang.OutOfMemoryError: PermGen space 2.java.lang.OutOfMemoryError: Java ... 
- java线上应用故障排查之二:高内存占用【转】
		前一篇介绍了线上应用故障排查之一:高CPU占用,这篇主要分析高内存占用故障的排查. 搞Java开发的,经常会碰到下面两种异常: 1.java.lang.OutOfMemoryError: PermGe ... 
- java线上服务问题排查
		1.业务日志相关 假设系统出现异常或者业务有异常,首先想到的都是查看业务日志 查看日志工具: less 或者more grep tail -f filename 查看实时的最新内容 ps:切忌vim直 ... 
- Java线上应用故障排查之一:高CPU占用
		一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. 以我们最近出现的一个实际故障为例,介绍怎么定位和解决这类问题. 根据top命令,发现PID为28555的Java进程占 ... 
- Java线上应用故障排查之一:高CPU占用 (转)
		一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. (友情提示:本博文章欢迎转载,但请注明出处:hankchen,http://www.blogjava.net/hank ... 
- Java线上应用故障排查之一:高CPU占用【转】
		近期java应用,CPU使用率一直很高,经常达到100%,通过以下步骤完美解决,分享一下. 方法一: 转载:http://www.linuxhot.com/java-cpu-used-high.htm ... 
- Java线上应用故障排查
		线上故障主要2种: CPU利用率很高, 内存占用率很大 一.CPU利用率很高 1. top查询那个进程CPU使用率高 2. 显示进程列表 ps -mp pid -o THREAD,tid,time 找 ... 
- Java线上应用故障之CPU占用高排查与定位
		最近线上频繁报警CPU空闲不足,故紧急排查后分享给大家 1.使用top命令,获取占用CPU最高的进程号 2.查看线程号对应的进程信息 命令:ps -ef|grep 22630 3.查看进程对应的线程信 ... 
随机推荐
- asp.net 中使用less
			首先 ,需要知道 whats the less; 实际上less 只是针对css比较难于维护和抽象这种现象,而创造的一个工具. 然后,在抛开语言环境的情况下(例如.net 是vs环境,java是ecl ... 
- Dao层和Service层设计
			1.Dao接口层 public interface IBaseDao<T, ID extends Serializable>{ public abstract Serializable s ... 
- 《PHP与MySQL WEB开发》读书笔记
			<PHP与MySQL WEB开发>读书笔记 作者:[美]Luke Welling PHP输出的HereDoc语法: echo <<<theEnd line 1 line ... 
- Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕
			Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕 今天会逐行解析一下SparkStreaming运行的日志,运行的是WordCountO ... 
- Natural Language Processing with Python - Chapter 0
			一年之前,我做梦也想不到会来这里写技术总结.误打误撞来到了上海西南某高校,成为了文科专业的工科男,现在每天除了膜ha,就是恶补CS.导师是做计算语言学的,所以当务之急就是先自学计算机自然语言处理,打好 ... 
- 64位Python安装PIL
			写个小程序需要安装PIL,但是官网只有32位,无法找到64位安装路径.根据网上教程自行编译,但是由于VS版本问题总是提示“Python error: Unable to find vcvarsall. ... 
- go语言实现线程池
			话说真的好久没有写博客了,最近赶新项目,工作太忙了.这一周任务比较少,又可以随便敲敲了. 逛论坛的时候突发奇想,想用go语言实现一个线程池,主要功能是:添加total个任务到线程池中,线程池开启num ... 
- easy ui datagrid 设置冻结列
			为了冻结列,您需要定义 frozenColumns 属性.frozenColumn 属性和 columns 属性一样. $('#tt').datagrid({ title:'Frozen Column ... 
- doc下批处理文件的感想
			这段时间忙着为我们的爬虫程序做一个守护进程,想来想去还是用脚本比较好,所以用了点时间仔细的研究了一下,这里有一点点经验想分享给大家,也不能说是经验了,只能说是我写这个的时候所用到的知识: 1.task ... 
- C# Windows - ListBox&CheckedListBox
			ListBox和CheckedListBox类的属性 属性 说明 SelectedIndex 这个值表明列表框中选中项的基于0的索引 ColumnWidth 在包含多个列的列表框中,这个属性指定列宽 ... 
