• java.io.IOException: Broken pipe


    最近,在服务器的日志里发现有 java.io.IOException: Broken pipe 这样的报错消息,我在网上搜了一下,貌似是因为客户端断开了连接,于是我在本地开发环境,用JMeter尝试复现了一下。

    环境

    • macOS Monterey 12.4
    • JDK 17.0.3
    • Eclipse 2021-12 (4.22.0)
    • IBM Liberty Developer Tools 22.1
    • JMeter 17.0.2 (8.86)

    API

    API代码如下:

    	@RequestMapping(value = "/dingtest0615_1", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
    	@ResponseBody
    	public JSONObject dingtest0615_1(HttpServletRequest request, HttpServletResponse response) {
    		response.setContentType("application/json; charset=utf-8");
    		JSONObject result = new JSONObject();
    		try {
    			result.put("aaa", "bbb");
    			Thread.sleep(1000 * 30);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		return result;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    API逻辑非常简单:

    • sleep 30秒,这是为了模拟一个比较耗时的API;
    • 返回一个简单的JSON对象;

    测试1(最简单的测试)

    客户端工具使用了JMeter(关于JMeter的简单用法,参见我另一篇文档),如下:

    在这里插入图片描述

    验证点:

    • API运行了30秒;
    • 返回了期望的JSON数据;

    测试2(取消请求)

    如果在请求还没有结束的时候取消请求:

    在这里插入图片描述

    最终如下:

    在这里插入图片描述

    客户端报错如下:

    java.net.SocketException: Socket closed
    	at java.base/sun.nio.ch.NioSocketImpl.endRead(NioSocketImpl.java:248)
    	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:327)
    	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
    	at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
    	at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
    	at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)
    	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
    	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
    	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
    	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
    	at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157)
    	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
    	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
    	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
    	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    	at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:939)
    	at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:650)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:66)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1301)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1290)
    	at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:651)
    	at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:570)
    	at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:501)
    	at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:268)
    	at java.base/java.lang.Thread.run(Thread.java:833)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    服务器报错如下:

    [ERROR   ] SRVE0777E: Exception thrown by application class 'sun.nio.ch.FileDispatcherImpl.writev0:-2'
    java.io.IOException: Broken pipe
    	at java.base/sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
    	at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:66)
    	at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:217)
    	at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:153)
    	at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:563)
    	at java.base/java.nio.channels.SocketChannel.write(SocketChannel.java:642)
    	at com.ibm.ws.tcpchannel.internal.NioSocketIOChannel.write(NioSocketIOChannel.java:205)
    	at [internal classes]
    	at java.base/java.io.FilterOutputStream.flush(FilterOutputStream.java:153)
    	at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1187)
    	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:459)
    	at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
    	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183)
    	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    	at dsweb.api.APIDispatcherServlet.doService(APIDispatcherServlet.java:24)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
    	at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1258)
    	at [internal classes]
    	at com.ibm.aps.tools.monitor.restapi.monitorV4.filter.URLPermissionFilter.doFilter(URLPermissionFilter.java:30)
    	at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)
    	at [internal classes]
    	at dsweb.filter.URLAccessServletFilter.handleURLAccess(URLAccessServletFilter.java:566)
    	at dsweb.filter.URLAccessServletFilter.doFilter(URLAccessServletFilter.java:169)
    	at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)
    	at [internal classes]
    
    [ERROR   ] Error Page Exception: 
    monitor
    /monitor
    Error Page Exception
    com.ibm.ws.webcontainer.webapp.WebAppErrorReport: java.io.IOException: Broken pipe
    	at java.base/sun.nio.ch.FileDispatcherImpl.writev0(Native Method)
    	at java.base/sun.nio.ch.SocketDispatcher.writev(SocketDispatcher.java:66)
    	at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:217)
    	at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:153)
    	at java.base/sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:563)
    	at java.base/java.nio.channels.SocketChannel.write(SocketChannel.java:642)
    	at com.ibm.ws.tcpchannel.internal.NioSocketIOChannel.write(NioSocketIOChannel.java:205)
    	at [internal classes]
    	at java.base/java.io.FilterOutputStream.flush(FilterOutputStream.java:153)
    	at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1187)
    	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:459)
    	at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
    	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:183)
    	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
    	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:135)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
    	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
    	at dsweb.api.APIDispatcherServlet.doService(APIDispatcherServlet.java:24)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
    	at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1258)
    	at [internal classes]
    	at com.ibm.aps.tools.monitor.restapi.monitorV4.filter.URLPermissionFilter.doFilter(URLPermissionFilter.java:30)
    	at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)
    	at [internal classes]
    	at dsweb.filter.URLAccessServletFilter.handleURLAccess(URLAccessServletFilter.java:566)
    	at dsweb.filter.URLAccessServletFilter.doFilter(URLAccessServletFilter.java:169)
    	at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:201)
    	at [internal classes]
    Caused by: java.io.IOException: Broken pipe
    	... 37 more
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    通过测试得到的错误消息,跟开头提到服务器里的错误消息基本一致。

    所谓broken pipe,应该是指客户端/服务器本来建立了连接,但是被客户端打破了,从服务器的角度看,连接被迫断开,所以报了这个错误。

    从功能角度看,貌似没有什么影响,因为是客户端主动断开了连接,不再等待处理请求的返回结果,而服务器补货到了异常,也不影响后续的服务。

    测试3(curl取消请求)

    我用 curl 命令来发同样的API请求,然后按 Ctrl + C 取消请求,在服务器端并不会产生这个错误,猜测curl可能跟JMeter的机制不一样吧。

    ➜  ~ curl -XGET 'http://localhost:9080/monitor/v4/metrics/dingtest0909' -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'X-DB-Profile: kai0831' --compressed --insecure -H "Authorization: Bearer ${token}" | jq .
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
      0     0    0     0    0     0      0      0 --:--:--  0:00:09 --:--:--     0^C
    ➜  ~ echo $?
    130
    ➜  ~
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试4(并发)

    如果在JMeter里并发运行1000个API请求,不取消请求,大部分请求很快就失败了,而有少量(测试多次,每次数量略有不同,比如有55个)个请求最终获得了成功。

    最终如下:

    在这里插入图片描述

    大部分请求失败了,有55个请求成功了。

    失败的请求,报错跟前面取消请求报错的消息略有不同,如下:

    java.net.SocketException: Connection reset
    	at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323)
    	at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
    	at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
    	at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
    	at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
    	at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
    	at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)
    	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:138)
    	at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
    	at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
    	at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
    	at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:157)
    	at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
    	at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
    	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
    	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
    	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    	at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.executeRequest(HTTPHC4Impl.java:939)
    	at org.apache.jmeter.protocol.http.sampler.HTTPHC4Impl.sample(HTTPHC4Impl.java:650)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy.sample(HTTPSamplerProxy.java:66)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1301)
    	at org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase.sample(HTTPSamplerBase.java:1290)
    	at org.apache.jmeter.threads.JMeterThread.doSampling(JMeterThread.java:651)
    	at org.apache.jmeter.threads.JMeterThread.executeSamplePackage(JMeterThread.java:570)
    	at org.apache.jmeter.threads.JMeterThread.processSampler(JMeterThread.java:501)
    	at org.apache.jmeter.threads.JMeterThread.run(JMeterThread.java:268)
    	at java.base/java.lang.Thread.run(Thread.java:833)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 取消请求,报错是 Socket closed
    • 并发数量太多,报错是 Connection reset

    测试5(并发 & 取消请求)

    在这里插入图片描述

    • 客户端:有的错误消息是 Socket closed (取消请求),有的错误消息是 Connection reset (并发太多);
    • 服务器:有很多个 java.io.IOException: Broken pipe 错误消息;
  • 相关阅读:
    dbt产品初体验
    互联网Java工程师面试题·Java 总结篇·第十弹
    Spring Boot集成xstream快速入门demo
    Python识别二维码的两种方法
    遥感技术让农业更“智慧”北斗在精准农业领域信息化农业化的特征
    css 样式 使用变量
    分布式.BASE理论
    【Golang星辰图】Go语言之光照耀数据科学:揭开强大库的神秘面纱
    leetcode 51. N 皇后
    word直播全部知识点
  • 原文地址:https://blog.csdn.net/duke_ding2/article/details/126782480