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

通过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



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

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/118535.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • Ubuntu20.04安装cuda10.1「建议收藏」

    Ubuntu20.04安装cuda10.1「建议收藏」安装前准备首先要查看你的NVIDIA显卡驱动是否支持cuda10.1版本。在终端执行以下命令:nvidia-smi如果**CUDAVersion:…**这里的版本号大于等于10.1(我这里的是10.2),就可以安装cuda10.1.关键点:gcc降级因为Ubuntu20.04自带的gcc版本为9.3,而cuda10.1不支持gcc-9,因此要手动安装gcc-7,命令如下:sudoapt-getinstallgcc-7g++-7安装完gcc-7,系统中就存在两个版本

  • 线程的IsBackground属性「建议收藏」

    线程的IsBackground属性「建议收藏」.Net的公用语言运行时(CommonLanguageRuntime,CLR)能区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。.net环境使用Thread建立的线程默认情况下是前台线程,即线程属性IsBackground=

    2022年10月17日
  • CentOs6.5升级内核到3.0+[通俗易懂]

    CentOs6.5升级内核到3.0+[通俗易懂]1、查看内核版本 命令: uname -a 2、导入key 命令: rpm –import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 如果报SSL错误, 则需要更新网络安全服务 yum update nss3、安装elrepo的yum源命令:rpm -U…

  • 机器学习面试题60~100「建议收藏」

    机器学习面试题60~100「建议收藏」61.说说梯度下降法  @LeftNotEasy,本题解析来源:http://www.cnblogs.com/LeftNotEasy/archive/2010/12/05/mathmatic_in_machine_learning_1_regression_and_gradient_descent.html  下面是一个典型的机器学习的过程,首先给出一个输入数据,我们的算法会通过一系列的过程得到一…

  • 查看mysql慢日志_docker查看实时日志的命令

    查看mysql慢日志_docker查看实时日志的命令慢查询日志是否开启showvariableslike’%slow_query_log%’;#如果结果中包含slow_query_log|OFF,则说明慢日志已经关闭#开启慢查询日志的方式:setglobalslow_query_log=1;慢查询sql的设置时间查看慢查询sql的设置时间,默认10s,sql执行时间大于该时间的才是慢sql,才会记录到慢查询…

    2022年10月12日
  • js addEventListener事件捕获与冒泡,第三个参数详解,阻止事件传播

    js addEventListener事件捕获与冒泡,第三个参数详解,阻止事件传播结论element.addEventListener(event,function[,useCapture])event:事件名称,如clickfunction:指定要事件触发时执行的函数,可以传入事件参数useCapture:可选。布尔值,指定事件是否在捕获或冒泡阶段执行。默认false:在冒泡阶段执行指定事件true:在捕获阶段执行事件event.stopPropagat…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号