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;
	}

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)

服务器报错如下:

[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

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

所谓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
➜  ~

测试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)
  • 取消请求,报错是 Socket closed
  • 并发数量太多,报错是 Connection reset

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

在这里插入图片描述

  • 客户端:有的错误消息是 Socket closed (取消请求),有的错误消息是 Connection reset (并发太多);
  • 服务器:有很多个 java.io.IOException: Broken pipe 错误消息;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值