通过jstack定位在线执行java系统故障_案例1

问题描写叙述:

在一个在线执行的java web系统中,会定时执行一个FTP上传的任务,结果有一天发现,文件正常生成后却没有上传。

问题初步分析:

1.查看日志文件

发现这个任务仅仅打印了開始进入FTP处理的日志,可是没有打印FTP处理完毕的日志。

从代码上看,FTP上传处理的代码异常保护都很的好,假设出现异常,就会进行打印,而日志文件里却没有相关的信息,甚是奇怪。怀疑是FTP过程问题,如对方FTPserver有什么问题导致,可是却找不到证据。

苦于无法窥探java执行系统内部信息,祭出杀手锏-jstack

2.通过jstack分析

在执行系统上,通过jps命令(也能够通过其它方式,如ps)查看执行中的java程序的进程ID,使用jstack
pid > jstack.log 将线程堆栈信息导出到jstack.log文件里,找到例如以下实用的信息。

通过代码确认,下方的UploadFtpTask确实就是我们的文件上传任务的运行代码。

通过堆栈信息看,线程状态为RUNNABLE,不是BLOCKED状态,说明不是由于锁导致线程堵塞,而是堵塞在了网络读取上。

<span style="font-size:14px;">"DefaultQuartzScheduler_Worker-5" prio=10 tid=0x00002aaaf4382801 nid=0x1874 runnable [0x000000004133b000..0x000000004133bda0]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.read(SocketInputStream.java:129)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
        - locked <0x00002aaac3cdd061> (a java.io.InputStreamReader)
        at sun.nio.cs.StreamDecoder.read0(StreamDecoder.java:107)
        - locked <0x00002aaac3cdd061> (a java.io.InputStreamReader)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:93)
        at java.io.InputStreamReader.read(InputStreamReader.java:151)
        at it.sauronsoftware.ftp4j.NVTASCIIReader.readLine(NVTASCIIReader.java:105)
        at it.sauronsoftware.ftp4j.FTPCommunicationChannel.read(FTPCommunicationChannel.java:142)
        at it.sauronsoftware.ftp4j.FTPCommunicationChannel.readFTPReply(FTPCommunicationChannel.java:187)
        at it.sauronsoftware.ftp4j.FTPClient.connect(FTPClient.java:1034)
        - locked <0x00002aaac3cdd109> (a java.lang.Object)
        at com.xx.FtpClientImpl.connect(FtpClientImpl.java:56)
        at com.xx.UploadFtpTask.execute(UploadFtpTask.java:88)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:216)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:549)</span>

通过引用的jar包确认,这个FTP功能使用的开源包ftp4j来实现的,使用的版本号为1.5.1

写个測试程序,看看FTP连接时的调用堆栈:

Socket.connect(SocketAddress) line: 469

Socket.<init>(SocketAddress, SocketAddress, boolean) line: 366

Socket.<init>(String, int) line: 180

DirectConnector.connect(String, int) line: 35

DirectConnector.connectForCommunicationChannel(String, int) line: 40

FTPClient.connect(String, int) line: 1024

FTPClient.connect(String) line: 991

Test.main(String[]) line: 19

而Socket 的469行是什么呢?

connect(endpoint, 0);

这个函数的定义为:public void connect(SocketAddress endpoint, int timeout)  ,上面的调用相当于设置了timeout为0,那就意味着出现网络丢包或者对端服务有问题时,这个连接会无限制等待下去。这就杯具了。

再看看这个开源项目兴许是否对此问题做过改动呢?下载1.7.2版本号,再次測试,查看调用堆栈:

Socket.connect(SocketAddress, int) line: 490

DirectConnector(FTPConnector).tcpConnectForCommunicationChannel(String, int) line: 208

DirectConnector.connectForCommunicationChannel(String, int) line: 39

FTPClient.connect(String, int) line: 1036

FTPClient.connect(String) line: 1003

Test.main(String[]) line: 19

通过tcpConnectForCommunicationChannel去调用Socket的connect方法时,传入了超时时间,为10秒(10*1000)。这就引入了超时机制,假设出现上面问题时,就不会死等了。

总结:

1.jstack工具是定位在线执行java系统的利器,能够查看线程堆栈信息,这对于分析问题很重要,特别是在日志分析和代码分析无法确定问题时。

2.网络连接时,必须设置超时,不能无限制等待。发散一下,开发系统时,必须考虑各种异常情况。套用那句话,出来混,总是要还的。

转载请注明出处:http://blog.csdn.net/u014569459/article/details/38542949





时间: 2024-11-06 10:38:25

通过jstack定位在线执行java系统故障_案例1的相关文章

通过jstack定位在线运行java系统故障_案例1

问题描述: 在一个在线运行的java web系统中,会定时运行一个FTP上传的任务,结果有一天发现,文件正常生成后却没有上传. 问题初步分析: 1.查看日志文件 发现这个任务只打印了开始进入FTP处理的日志,但是没有打印FTP处理完成的日志. 从代码上看,FTP上传处理的代码异常保护都非常的好,如果出现异常,就会进行打印,而日志文件中却没有相关的信息,甚是奇怪.怀疑是FTP过程问题,如对方FTP服务器有什么问题导致,但是却找不到证据. 苦于无法窥探java运行系统内部信息,祭出杀手锏-jstac

代码在线执行工具(PHP,Java,C++ 等)

http://www.it1352.com/Onlinetools 支持几十种语言的在线运行. 缺点:对请求频率限制太严格了,一分钟不到十次吧...可以清理浏览器 Cookie 之后重新访问.必须用示例中的 Rextester 类作为类名. 可以嵌入到自己网站,比如 Java 嵌入语句如下: <iframe src="http://www.it1352.com/Onlinetools/OnlineCompileCommon/4?c_height=100&r_height=100&a

java开发_&quot;&quot;和null的区别

今天在工作中遇到一个问题: 在代码中: 1 //name可以为"",即:name == "" 2 //但是name不可以为null,即:name != null 下面是java中的null和""区别: 1 null和""的区别 2 问题一: 3 null和""的区别 4 String s=null; 5 string.trim()就会抛出为空的exception 6 String s=""

Oracle性能优化之执行计划管理_超越OCP精通Oracle视频教程培训31

Oracle性能优化之执行计划管理_超越OCP精通Oracle视频教程培训31 本课程介绍: Oracle视频教程,风哥本套oracle教程培训<<Oracle数据库性能优化培训教程>>的第1/10套:Oracle性能优化之执行计划管理.主要学习Oracle性能优化简介,SQL 语句处理流程,软解析和硬解析,绑定变量及案例,游标的介绍,Oracle的优化器,执行计划的查看,SQL语句访问路径,SQL语句的连接方式,Oracle驱动表,执行计划的干预,常用hint提示的使用. 视频教

Java泛型_上界extends_下界super

?Java泛型_上界extends_下界super ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T或是T的子类 <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型(T)的超类型(父类型),直至Object 当使用 Upper Bound 通配符时 如下代码, /**  * 代码中通配符<?> 是 <? extends Object> 的简写  *  * @param list

dos界面下执行java文件将错误输出到一个文本小技巧

如果dos下执行java出现错误,把错误记录到一个文档 正确时如图,输出结果为hello,我把String的s改为小写,出现错误,用2>命令输出到error.txt在当前目录就出现了error.txt文件

执行Java -jar somefile.jar时发生了什么(二)

(6)Java.c中的LoadMainClass 位置jdk/src/share/bin/java.c 该方法负责加载main函数所在的类.该方法首先加载sun.launcher.LauncherHelper类,然后调用该类的checkAndLoadMain去找到main函数所在的类,相关代码如下. jclass cls = GetLauncherHelperClass(env);//这个函数加载了sun.launcher.LauncherHelper类 NULL_CHECK0(cls); if

如何使用命令行cmd执行java程序

如果你的电脑上没有像idea eclipse这类的IDE,但是因为工作需要必须要执行java代码怎么办呢? 这个时候就需要使用电脑最原始的执行方式 既命令行 1:首先你得安装了jdk与jre (这里就请自习查阅资料) 2:找到你的java程序工作区中的bin目录并复制下来   eg:bin目录即是java代码编译后的文件目录 如下: 我们发现这里面有很多.class文件,这里面既是我们编译后的文件 3:进入cmd(win+r  输入cmd回车) 4:进入你的java所在的盘位 如下:输入d: 回

cmd上执行java命令 - Could not find or load main class

成功的安装了JDK和Eclipse后,在开发测试Java工程中,很少会遇到开发环境问题. 这都归功于Eclise通过工程(project)和包(package)把这些管理好. 但偶尔在命令行下编译和运行Java文件时,还会遇到如下错误:(以下示例都是在Win7上进行)D:\temp> java Tmp 有时java源程序中package设置不当也会导致上述错误.1. 在java源文件开头没有包声明语句 package; D:\temp> javac Tmp.javaD:\temp> ja