java.io.IOException 断开的管道【面试+工作】

java.io.IOException 断开的管道 解决方法 ClientAbortException: java.io.IOException: Broken pipe

【面试+工作】

查看采集数据的tomcat日志,习惯性的先翻到日志的最后去查看有没有异常的打印,果然发现了好几种异常信息,但是最多还是这个:

“Too manay open files” 问题很明显啊,文件描述符超出限制导致无法打开文件或创建网络连接,这个问题又会导致一些其它问题的产生,肯定是ulimit没有优化,于是检查ulimit的设置;

open files竟然是65535,已经做过了优化,是不是先启动的tomcat等服务,然后才对ulimit做的优化?有可能,这样的话重启一下服务就ok了,于是将全部服务重启了一遍,运行正常了,不一会报表就显示数据了,然后告诉技术支持,问题已经解决了,然后就去处理别的case了;

结果还不到20分钟,技术支持说,报表又没有数据了,于是又打数据采集的应用的tomcat日志查看,发现了一堆异常,全都是一个错:

这个异常非常多,看报错信息,是tomcat的connector在执行写操作的时候发生了Broken pipe异常,connector是tomcat处理网络请求的,难道是网络出问题了,但是为什么发生异常的都是写,读就没问题呢?为了判断是不是网络问题,于是用wget命令在本地访问了一下服务器的一个接口,结果发现等了好久都没有响应,正常情况下应该是马上就有响应的,这说明不是网络的原因,是服务器的问题,又用命令查看了下当前tcpip连接的状态:

CLOSE_WAIT 状态的连接竟然有3853个,这太不正常了,这说明是客户端先关闭了连接,服务器端没有执行关闭连接的操作,导致服务器端一直维持在CLOSE_WAIT的状态,如果不对操作系统的keepalive做优化,这个状态默认会维持两个小时,查看了下系统的设置:

果然是7200秒,这就解释通了,为什么第一次查看tomcat日志最后报错都是“Too manay open files”异常,一定是在两个小时内,close_wait状态暴增,导致文件描述符超过了65535的最大限制;

而这个状态应该就是broken pipe 异常导致的,是什么导致的broken pipe异常呢?为什么探针关闭了连接,但是数据采集服务器却没有关闭连接?报异常的是tomcat的connector,tomcat不可能会忘记调用close方法去关闭连接,排除了程序的问题,也想不出来是什么导致的了;

于是去拿了往采集服务器上传数据的探针的日志查看,竟然有大量的一个异常:

都是read time out异常,那么问题就明确了, 是探针端读取超时了,断开了连接,而这时候数据采集服务器还在处理请求,它并不知道探针端已经断开了连接,处理完请求后再将处理结果发给探针,就broken pipe了;

原来这个异常是客户端读取超时关闭了连接,这时候服务器端再向客户端已经断开的连接写数据时就发生了broken pipe异常!

探针读超时的时间是2分钟,服务器为什么这么长的时间都没有响应呢?于是使用jstack命令导出了tomcat的线程栈信息进行分析,最后发现代码中有耗时的操作加了锁,导致线程阻塞(保密原因,在这里就不贴代码了);

这里总结一下,给我发私信的有些朋友没有get到Broken piple问题的重点,并不是只有超时才会导致这个问题,只要是连接断开,再往这个断开的连接上去执行写操作,都会出现这个异常,客户端超时断开只是其中的一种情况:

另外,当看到“Too manay open files”异常的时候,通常做法除了检查ulimit系统限制外,还应该看一下进程打开的文件句柄数,cat /proc/sys/fs/file-nr命令查看系统总句柄数,当前应用打开的文件句柄数使用ls -l /proc/<pid>/fd | wc -l命令,这里还好忽略了这一步,否则可能又要花费一些时间来查找系统真正的问题;

通过这个案例可知,排查问题时,在有些情况下,你第一眼看到的异常信息未必就是问题的根源所在,而是后续一些连锁反应,尤其是当大量出现同一个异常的情况下,不要看最后一条异常日志,应该先去日志里面查找第一出现该异常的位置,看看这个异常发生之前系统的状况;

java tcp/ip异常

1 java.net.SocketTimeoutException .

这 个异 常比较常见,socket 超时。一般有 2 个地方会抛出这个,一个是 connect 的 时 候 , 这 个 超 时 参 数 由connect(SocketAddress endpoint,int timeout) 中的后者来决定,还有就是 setSoTimeout(int timeout),这个是设定读取的超时时间。它们设置成 0 均表示无限大。

2 java.net.BindException:Address already in use: JVM_Bind

该 异 常 发 生 在 服 务 器 端 进 行 new ServerSocket(port) 或者 socket.bind(SocketAddress bindpoint)操作时。

原因:与 port 一样的一个端口已经被启动,并进行监听。此时用 netstat –an 命令,可以看到一个 Listending 状态的端口。只需要找一个没有被占用的端口就能解决这个问题。

3 java.net.ConnectException: Connection refused: connect

该异常发生在客户端进行 new Socket(ip, port)或者 socket.connect(address,timeout)操作时,原 因:指定 ip 地址的机器不能找到(也就是说从当前机器不存在到指定 ip 路由),或者是该 ip 存在,但找不到指定的端口进行监听。应该首先检查客户端的 ip 和 port是否写错了,假如正确则从客户端 ping 一下服务器看是否能 ping 通,假如能 ping 通(服务服务器端把 ping 禁掉则需要另外的办法),则 看在服务器端的监听指定端口的程序是否启动。

4 java.net.SocketException: Socket is closed

该异常在客户端和服务器均可能发生。异常的原因是己方主动关闭了连接后(调用了 Socket 的 close 方法)再对网络连接进行读写操作。

5 java.net.SocketException: Connection reset 或者Connect reset by peer:Socket write error

该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是假如一端的 Socket 被关闭(或主动关闭或者因为异常退出而引起的关闭), 另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另 一 端 假 如 在 从 连 接 中 读 数 据 则 抛 出 该 异 常(Connection reset)。简单的说就是在连接断开后的读和写操作引起的。

还有一种情况,如果一端发送RST数据包中断了TCP连接,另外一端也会出现这个异常,如果是tomcat,异常如下:

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Connection reset by peer

阿里的tcp方式的健康检查为了提高性能,省去挥手交互,直接发送一个RST来终断连接,就会导致服务器端出现这个异常;

对于服务器,一般的原因可以认为:

a) 服务器的并发连接数超过了其承载量,服务器会将其中一些连接主动 Down 掉.

b) 在数据传输的过程中,浏览器或者接收客户端关闭了,而服务端还在向客户端发送数据。

6 java.net.SocketException: Broken pipe

该异常在客户端和服务器均有可能发生。在抛出SocketExcepton:Connect reset by peer:Socket write error 后,假如再继续写数据则抛出该异常。前两个异常的解决方法是首先确保程序退出前关闭所有的网络连接,其次是要检测对方的关闭连接操作,发现对方 关闭连接后自己也要关闭该连接。

对于 4 和 5 这两种情况的异常,需要特别注意连接的维护。在短连接情况下还好,如果是长连接情况,对于连接状态的维护不当,则非常容易出现异常。基本上对长连接需要做的就是:

a) 检测对方的主动断连(对方调用了 Socket 的 close 方法)。因为对方主动断连,另一方如果在进行读操作,则此时的返回值是-1。所以一旦检测到对方断连,则主动关闭己方的连接(调用 Socket 的 close 方法)。

b) 检测对方的宕机、异常退出及网络不通,一般做法都是心跳检测。双方周期性的发送数据给对方,同时也从对方接收“心跳数据”,如果连续几个周期都没有收到 对方心跳,则可以判断对方或者宕机或者异常退出或者网络不通,此时也需要主动关闭己方连接;如果是客户端可在延迟一定时间后重新发起连接。虽然 Socket 有一个keep alive 选项来维护连接,如果用该选项,一般需要两个小时才能发现对方的宕机、异常退出及网络不通。

7 java.net.SocketException: Too many open files

原因: 操作系统的中打开文件的最大句柄数受限所致,常常发生在很多个并发用户访问服务器的时候。因为为了执行每个用户的应用服务器都要加载很多文件(new 一个socket 就需要一个文件句柄),这就会导致打开文件的句柄的缺乏。

解决方式:

a) 尽量把类打成 jar 包,因为一个 jar 包只消耗一个文件句柄,如果不打包,一个类就消耗一个文件句柄。

b) java 的 GC 不能关闭网络连接打开的文件句柄,如果没有执行 close()则文件句柄将一直存在,而不能被关闭。

也可以考虑设置 socket 的最大打开 数来控制这个问题。对操作系统做相关的设置,增加最大文件句柄数量。

ulimit -a 可以查看系统目前资源限制,ulimit -n 10240 则可以修改,这个修改只对当前窗口有效。

8 Cannot assign requested address

1. 端口号被占用,导致地址无法绑定:

java.net.BindException: Cannot assign requested address: bind:是由于IP地址变化导致的;

2. 服务器网络配置异常:

/etc/hosts 中配置的地址错误;

3.还有一种情况是执行ipconfig 发现没有环路地址,这是因为环路地址配置文件丢失了;

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2018-08-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

HTTP 协议漫谈

简介 网络上已经有不少介绍 HTTP 的好文章,对HTTP的一些细节介绍的比较好,所以本篇文章不会对 HTTP 的细节进行深究,而是从够高和更结构化的角度将 H...

29511
来自专栏Golang语言社区

HTTP协议漫谈

简介 园子里已经有不少介绍HTTP的的好文章。对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将H...

3796
来自专栏云计算教程系列

如何在Ubuntu 14.04上使用Pydio托管文件共享服务器

随着云的采用增加,越来越多的数据被远程存储。从音乐到图片再到个人文档,很多人都将文件上传到他们不管理的服务器上。如果您希望将文件保存在您控制的服务器上,则可以使...

3390
来自专栏三杯水

系统重启后nginx reload不生效原因分析

这是一种比较少见,困扰我很久的问题,虽然这个问题很简单,但是找到根本原因还是费了不少时间,现在把分析过程分享如下。

3142
来自专栏java沉淀

用自己的电脑做网站服务器,实现外网访问

网站服务器其实就是一台大型的电脑主机,我们也可以将自己家的电脑主机去做成一台用于存放网站的网站小型服务器供别人访问。那么如何用自己的电脑去做网站服务器呢?由于...

8.3K8
来自专栏运维

系统重启后ngix reload不生效原因分析

这是一种比较少见,困扰我很久的问题,虽然这个问题很简单,但是找到根本原因还是费了不少时间,现在把分析过程分享如下。

872
来自专栏运维

OpenResty Codis集群缓存系统

客户端------OR入口------Codis缓存------Nginx反向代理------IIS源站

1631
来自专栏用户2442861的专栏

每天一个linux命令(61):wget命令

http://www.cnblogs.com/peida/archive/2013/03/18/2965369.html

1412
来自专栏Golang语言社区

HTTP协议漫谈

简介 园子里已经有不少介绍HTTP的的好文章。对HTTP的一些细节介绍的比较好,所以本篇文章不会对HTTP的细节进行深究,而是从够高和更结构化的角度将H...

35213
来自专栏Linux运维学习之路

Linux分区的注意事项以及远程连接排错

分区方式一般有三种 第一种:数据不是很重要 /boot(系统的引导分区): 系统引导的信息/软件 系统的内核   200M swap( 交换分区): 为了避免系...

21910

扫码关注云+社区

领取腾讯云代金券