我有一个Apache CXF 2.7.8使用者调用另一个SOAP Web服务。
在我的开发环境(Tomcat 6.0,jdk1.7.0_51,Windows 7)中,一切都很迷人。
然而;当我将代码部署到测试环境(WebLogic 12.1,jdk1.7.0_51,RHEL 6)时,我得到javax.xml.ws.WebServiceException: Could not send Message
异常,由java.net.SocketTimeoutException: Read time out after x millis
每秒发出一次。
开发和测试实例都调用完全相同的服务器。
当我执行网络跟踪时,我看到CXF使用相同的套接字连接发送了许多请求(感谢HTTP Keep-Alive)。最终,服务器发送FIN
表示客户端应该停止使用此连接(如果需要,建立一个新连接)。客户端确认FIN
,但随后继续在同一套接字上发送下一个请求,尽管已被告知断开连接(并确认该指令)。然后服务器发送RST
(如预期的那样),告诉客户端消失。然后客户端再次尝试。最终,我们达到Read超时已经过了足够的时间,并且抛出了上面的SocketTimeoutException。
(顺便说一句:在Windows开发平台上,客户端尊重FIN
并为下一个请求建立新的套接字连接。)
当我禁用HTTP Keep-Alive时(使用说明here),服务器只在客户端发送一个请求后发送FIN
(完全如此)。客户端仍然为该帧确认FIN
ACK
,然后大胆继续尝试使用该套接字。
我很乐意让HTTP Keep-Alive正常工作,但如果没有它,我会满足于工作。
是否有任何建议的解决方案或后续步骤进行故障排除?
答案 0 :(得分:3)
这是我们到目前为止所学到的,希望它可以帮助其他人:
在Oracle JRE 1.7.0_51-b13中,当用户java.net.HttpURLConnection和javax.net.ssl.HttpsURLConnection(java.net.URLConnection的两个子类)启用HTTP KeepAlive时,服务器终止HTTP连接(因为它允许按照RFC进行),JRE不适当地继续使用断开连接的套接字(当该套接字处于看似FIN_WAIT状态之一时)。这样做,JRE"等待"套接字发送(永远不会返回响应),直到读取超时发生,抛出套接字超时异常。此功能在WebSphere下的IBM JRE中正常工作,但在WebLogic下的Oracle JRE中不能正常工作。
在同一个Oracle JRE版本中,当"连接:" HTTP或HTTPS请求上的标头字段设置为"关闭" (而不是Keep-Alive),根据RFC,URLConnection的子类继续尝试重用相同的底层套接字,即使它们不应该。
我们的解决方法是设置" http.keepAlive"系统属性为" false"禁用所有连接上的活动。这不是一个可接受的长期解决方法,因为在每个请求上设置和分解连接所需的额外时间和资源开销是不可接受的 - 我们必须继续努力以使其正常工作。
答案 1 :(得分:2)
<强> tldr;将-Dhttp.keepalivecache.sockethealthchecktimeout=10
添加到WebLogic服务器的JVM参数中。
这是我们最终学到的东西:
客户端(WebLogic 12c上的Apache 2.7.8)正在向服务器(而不是WebLogic服务器)发送SOAP HTTP请求。
服务器(至少在某些情况下)无法发送连接&#39;响应中的标头。这导致WebLogic不知道它是否可以重用连接。当它试图重用已被服务器关闭的连接时,我们得到了错误。
WebLogic有一个参数可以指示它在重用之前对重用的连接执行运行状况检查,如果它未通过运行状况检查则从池中逐出。设置系统属性&#39; http.keepalivecache.sockethealthchecktimeout&#39;一个非常低的值(比如10,持续10毫秒)解决了这个问题。