此问题的最常见原因之一是客户端在执行任何操作(如加载页面或下载附件)时关闭打开的连接。当使用 Nginx 之类的代理/负载均衡器(例如关闭 Web 浏览器甚至简单地取消下载)或连接速度很慢时,强制关闭某些连接也会发生这种情况。
一个简单的场景:浏览器向服务器请求资源,作为响应,服务器向浏览器返回响应。如果在服务器向浏览器发送响应时用户关闭了浏览器怎么办?服务器与浏览器之间的连接意外关闭。然后这会导致 Broken Pipe,该异常被称为 java.io.IOException: Broken Pipe in Java。
这也可能发生在任何中断客户端和服务器之间连接的事情上,包括性能问题甚至网络间歇性问题。
并非每个 Broken Pipe 异常都是开发人员的错
公平地说,这不是一个危险信号,因为它很大程度上是由用户的正常行为引起的,并且总是有可能由于某些故障而关闭服务。但是,如果服务器一次运行在相对大量的用户请求上,那么不仅是 Broken Pipe,而且任何异常似乎都会造成问题。
在我的例子中,由于高网络流量,日志被损坏的管道异常淹没。因为,写入文件(I/O 操作)是服务器执行的昂贵操作之一,想象一下服务器被与 Broken Pipe 相关的异常淹没,并且服务器必须投入大量资源才能将该异常堆栈跟踪写入日志文件。这导致服务器响应缓慢并使其迟缓。
在这一点上,我意识到,当扩展到大流量时,YES BROKEN PIPE EXCEPTION 是一个红色信号。
处理或移除破损管道的挑战
该系统使用 Wildfly 10.1 作为应用程序服务器,并在 JavaEE 7 上编写。处理这种情况对我来说不是小菜一碟,因为:
在本地或 QA 环境中复制此异常需要正确对齐所有行星(开个玩笑),但是是的,这太难了。
在 Java 中处理异常很容易,只要在 catch 块中捕获异常即可。未处理异常的性质:java.io.IOException: Broken pipe 是这样的,它从 Wildfly 容器中引发并在堆栈跟踪中注销,而不是被困在 catch 块中。现在,想象一下必须处理无法从代码中捕获的异常。天哪!!!!
您永远不会知道,哪个请求引发了问题,因为服务器收到大量请求,其中任何一个都可能是异常的原因。将日志与套接字端点一起添加到每个 REST 端点是不可行的。
修复 java.io.IOException : Broken Pipe
最后,经过这么多断章取义的谈话,这里是主要部分(希望它值得等待)。
从系统中删除异常的两种方法是:
调查异常的根本原因,并消除它。
使用适当的日志记录或某些操作来优雅地处理异常。
消除根本原因
要求用户不要意外关闭连接
这是不可能的,看在上帝的份上