当我的用户连接他们的 Android 设备以输出 JSON Rest 服务时,我不时收到以下异常:
java.io.IOException: Socket read failed
at org.apache.coyote.ajp.AjpProcessor.read(AjpProcessor.java:313)
at org.apache.coyote.ajp.AjpProcessor.readMessage(AjpProcessor.java:364)
at org.apache.coyote.ajp.AjpProcessor.receive(AjpProcessor.java:331)
at org.apache.coyote.ajp.AbstractAjpProcessor.refillReadBuffer(AbstractAjpProcessor.java:614)
at org.apache.coyote.ajp.AbstractAjpProcessor$SocketInputBuffer.doRead(AbstractAjpProcessor.java:1065)
at org.apache.coyote.Request.doRead(Request.java:422)
at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:290)
at org.apache.tomcat.util.buf.ByteChunk.substract(ByteChunk.java:431)
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:315)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:200)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.ensureLoaded(ByteSourceBootstrapper.java:340)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.detectEncoding(ByteSourceBootstrapper.java:137)
at org.codehaus.jackson.impl.ByteSourceBootstrapper.constructParser(ByteSourceBootstrapper.java:197)
at org.codehaus.jackson.JsonFactory._createJsonParser(JsonFactory.java:542)
at org.codehaus.jackson.JsonFactory.createJsonParser(JsonFactory.java:389)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1454)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:124)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.readWithMessageConverters(HandlerMethodInvoker.java:641)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:605)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:354)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:171)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
我在跑步
- 阿帕奇/2.2.20
- mod_jk 1.2.36
- 雄猫 7.0.27
这可能与超时有关吗?就像客户端关闭连接并且服务器无法再从套接字读取一样?或者更有可能是服务器配置的问题?
更新:
执行一些 Apache 日志 awk,我发现以下 Apache 日志行与那些 Tomcat 日志异常相对应:
192.186.30.116 - - [25/Jun/2012:10:47:14 +0200] "POST /myapp/methodX HTTP/1.1" 400 145 "-" "clientApp BlackBerry9360/7.0.0.530 VendorID/168" 10012655
192.186.30.120 - - [25/Jun/2012:10:53:13 +0200] "POST /myapp/methodY HTTP/1.1" 400 145 "-" "clientApp BlackBerry9800/6.0.0.668 VendorID/124" 10012164
192.186.30.116 - - [25/Jun/2012:10:53:36 +0200] "POST /myapp/methodZ HTTP/1.1" 400 145 "-" "clientApp BlackBerry9360/7.0.0.530 VendorID/168" 10012677
192.82.68.16 - - [25/Jun/2012:11:22:31 +0200] "POST /myapp/methodX HTTP/1.1" 400 145 "-" "clientApp BlackBerry9930/7.1.0.402 VendorID/104" 10012667
192.82.68.16 - - [25/Jun/2012:11:23:21 +0200] "POST /myapp/methodZ HTTP/1.1" 400 145 "-" "clientApp BlackBerry9930/7.1.0.402 VendorID/104" 10012562
您可以看到针对这些请求发送给客户端的状态代码 400 Bad Request。
行尾的大数字(例如 10012562)显示请求在服务器上处理的时间(以微秒为单位):10012562 = 大约 10 秒
看起来连接在十秒后以某种方式终止了?我查看了 AJP 配置,但没有定义超时 - 10 秒将是我未使用的异步请求的超时
我找到了原因。问题是由 Apache 模块 mod_reqtimeout 的默认配置引起的:
我猜 BlackBerry 客户受到的打击更大,因为通过 RIM BIS 基础设施发送请求正文需要更长的时间。
将该值设置为 100 秒并监控客户端是否仍然受到影响。
看起来是超时了,但是你试过(或者有可能)直接通过Tomcat访问REST服务吗?(并且不通过 apache/ajp)。如果您尝试并发现您不再获得这些异常,则可能是 apache2/mod_jk 问题。
在我之前的工作中,我发现 mod_jk 的某些版本与 apache2 一起工作得更好(当然,我们并没有真正对它进行严格测试,我们只是使用了似乎在任何地方都可以工作的版本而没有改变它们,因为没有必要)