错误号org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe

        在说这个错误之前,我先介绍下背景,我们项目用的是SpringBoot框架,集成Hprose+spring+mybatis,Hprose是什么,可以参考我上篇对Hprose的一个简单介绍。当前项目业务是抓取一个网站近5年的足球篮球的赔率数据。所以这是个按照日期进行的一个大循环。介于Hprose特性,Hprose服务端的处理时间会特别长,这是个重点。

        在项目上线抓取数据时,linux环境下,我们的程序出现了这样一个错误,如下:

2016-06-16 12:47:52.190  WARN 10150 --- [http-nio-8082-exec-2] o.a.commons.httpclient.HttpMethodBase    : Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.
2016-06-16 12:52:30.077  WARN 10150 --- [http-nio-8082-exec-3] o.apache.catalina.core.AsyncContextImpl  : onTimeout() failed for listener of type [org.apache.catalina.core.AsyncListenerWrapper]

java.lang.NullPointerException: null
        at hprose.server.HproseService.getErrorMessage(HproseService.java:512)
        at hprose.server.HproseService.sendError(HproseService.java:522)
        at hprose.server.HproseHttpService$1.onTimeout(HproseHttpService.java:208)
        at org.apache.catalina.core.AsyncListenerWrapper.fireOnTimeout(AsyncListenerWrapper.java:40)
        at org.apache.catalina.core.AsyncContextImpl.timeout(AsyncContextImpl.java:155)
        at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:292)
        at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1715)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

2016-06-16 12:52:30.084  INFO 10150 --- [http-nio-8082-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'springMvc'
2016-06-16 12:52:30.084  INFO 10150 --- [http-nio-8082-exec-3] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'springMvc': initialization started
2016-06-16 12:52:30.086  INFO 10150 --- [http-nio-8082-exec-3] .s.AnnotationConfigWebApplicationContext : Refreshing WebApplicationContext for namespace 'springMvc-servlet': startup date [Thu Jun 16 12:52:30 GMT 2016]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@1ed431e9
2016-06-16 12:52:30.145  INFO 10150 --- [http-nio-8082-exec-3] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'springMvc': initialization completed in 61 ms
2016-06-16 12:52:30.176  INFO 10150 --- [http-nio-8082-exec-3] c.z.d.i.web.interceptor.LogInterceptor   : 请求日志,ip=127.0.0.1,uri=/error,params={}
2016-06-16 12:52:30.230 ERROR 10150 --- [http-nio-8082-exec-3] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
        at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393)
        at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:342)
        at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:317)
        at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:110)
        at com.fasterxml.jackson.core.json.UTF8JsonGenerator.flush(UTF8JsonGenerator.java:1044)
        at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:854)
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:265)
        at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
        at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
        at org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
        at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:870)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:720)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:468)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:391)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:318)
        at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:445)
        at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:304)
        at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:399)
        at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:460)
        at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:293)
        at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1715)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:652)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: Broken pipe
        at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
        at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
        at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
        at sun.nio.ch.IOUtil.write(IOUtil.java:65)
        at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471)
        at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:124)
        at org.apache.tomcat.util.net.NioBlockingSelector.write(NioBlockingSelector.java:101)
        at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:172)
        at org.apache.coyote.http11.InternalNioOutputBuffer.writeToSocket(InternalNioOutputBuffer.java:139)
        at org.apache.coyote.http11.InternalNioOutputBuffer.addToBB(InternalNioOutputBuffer.java:197)
        at org.apache.coyote.http11.InternalNioOutputBuffer.access$000(InternalNioOutputBuffer.java:41)
        at org.apache.coyote.http11.InternalNioOutputBuffer$SocketOutputBuffer.doWrite(InternalNioOutputBuffer.java:320)
        at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:116)
        at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:256)
        at org.apache.coyote.Response.doWrite(Response.java:501)
        at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:388)
        ... 41 common frames omitted

2016-06-16 12:52:30.240  INFO 10150 --- [http-nio-8082-exec-3] c.z.d.i.web.interceptor.LogInterceptor   : 请求日志,ip=127.0.0.1,uri=/port,params={}
2016-06-16 12:52:30.244 ERROR 10150 --- [http-nio-8082-exec-3] o.a.c.c.C.[Tomcat].[localhost]           : Exception Processing ErrorPage[errorCode=0, location=/error]

       这个错误是在tomcat启动运行后的3分钟左右出现。这个错误,表面上来看,在tomcat容器中运行过程中,出现null错误。我在网上找到一些对于此错误的相关解决办法,有的人说是项目打出的日志太多才导致的这个错误,清理相关日志之后,错误仍然出现。

        难道是我项目出现了什么问题才导致的tomcat容器停止的?于是我在日志中找到出现错误的那一天,开始进行测试,发现一个奇怪的现象,本地项目运行大概10min中左右Hprose的服务端出现null错误,但是紧接着会跳过这个错误,相当于重新启动tomcat,继续向前进行,如下图:

错误号org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe_第1张图片


与此同时,Hprose的客户端停止,出现以下错误:


错误号org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe_第2张图片

        难道是我项目处理的不规范,某个值为空了?所以导致Hprose客户端停止,可是这个时候tomcat为什么会重连,而且还能链接成功?

        这些都是问题,我将项目中的方法都用try catch包裹,然后找到出现这个错误前打出的日志,根据这个日志设置了断点,可是不巧的是,这个错误在这个时候不出现了,可是却在运行大概10分钟左右的时候再次出现,而且并未出现我catche到的日志记录。

       就这样排除是程序代码的问题。我告诉老大后,老大猜测我用的Hprose客户端是java的,他用的Hprose客户端是PHP的,是不是客户端的问题。虽然老大这么说了,但是我觉得java的Hprose客户端和PHP的Hprose客户端,除了语言不一样,调用方式不一样之外,其他的没什么区别啊?

       于是我就想着避免Hprose的调用,改走rest调用。我把项目改成rest风格后,项目运行一段时间后报这个错误,如图:

错误号org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe_第3张图片

别忘记,rest风格的项目在调用的时候其实使用的是Http请求。

       说到这里,我就明白这个错误大概是怎么产生的了,产生这个错误的原因,还得从Hprose说起。Hprose是一个属于RPC框架风格的框架,其实不管是什么RPC框架风格还是DI框架风格还是Rest风格,涉及到这种客户端服务端,其实最终都会归结到网络传输。所以这是个网络传输问题,服务端在没有走完自己的服务,客户端已经停止了,所以才有这个错误。Hprose有一个属性是延长服务端时间,只要修改这个属性,就好了。

       因此修改Hprose属性如下:

错误号org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe_第4张图片

      再次测试, 问题解决。

总结:

       通过这个问题,让我跟进一步认识到HProse,了解到不管是什么框架风格,管你什么DI、Rest、Rpc,最终归根到底所谓的远程调用都需要走到网络传输。知其然还要知其所以然。




你可能感兴趣的:(Hprose,分布式应用,JAVA项目实战经验)