【问题标题】:CXF, Camel and Spring thread blocking issueCXF、Camel 和 Spring 线程阻塞问题
【发布时间】:2014-09-18 14:35:37
【问题描述】:

问题在于 Camel 和 CXF(端点和客户端)以及同时触发的多个请求。

这是我们得到的异常:

java.net.SocketException: Unexpected end of file from server
    at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:772)
    at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:633)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1323)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
    at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:266)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1543)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1513)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1318)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:632)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:570)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:479)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)

我尝试使用 SoapUI 负载测试直接命中端点,但无法重现该问题。它只会通过 spring jaxws:client bean 发生。

来自客户端的一次请求可以正常工作,我们永远不会看到错误,只有当我们尝试执行多个请求时。

还在线程等待时执行了线程转储,所有请求(其中 5 个)如下所示:

http-listener-1(1)" daemon prio=5 tid=0x00007fa2843e8800 nid=0x9d07 in Object.wait() [0x000000018a266000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000001708b27e8> (a org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit$AsyncWrappedOutputStream)
    at org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit$AsyncWrappedOutputStream.getHttpResponse(AsyncHTTPConduit.java:562)
    - locked <0x00000001708b27e8> (a org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit$AsyncWrappedOutputStream)
    at org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit$AsyncWrappedOutputStream.getResponseCode(AsyncHTTPConduit.java:674)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1543)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1513)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1318)
    at org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit$AsyncWrappedOutputStream.close(AsyncHTTPConduit.java:383)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:632)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    - locked <0x00000001704175f8> (a org.apache.cxf.phase.PhaseInterceptorChain)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:570)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:479)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:382)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:335)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)

我也尝试过使用异步客户端,虽然堆栈跟踪和线程转储看起来不同,但结果是一样的。

这似乎也只发生在我们的开发实例(Mac 笔记本电脑)上,我们在带有 JDK 1.7.x 的 Glassfish 4.0 中运行它(我的机器上为 1.7u65,其他版本略有不同)

其中一条骆驼路线,虽然它似乎会影响所有路线(并且它们的设置方式相同)

from("cxf:/structure?serviceClass=" + StructureEndpoint.class.getName() + "&loggingFeatureEnabled=true")
            .routeId("structure")
            .to("log:com.test.camel")
            .recipientList(simple("direct:structure:${header.operationName}"));

发生这种情况时,我从未看到由 loggingFeatureEnabled 启用的 camel/cxf 日志输出,因此我们也看不到 .to("log:*") 输出。它永远不会到达这里。

可重复测试:

SoapUI,简单的负载测试。在 5 处开始/结束线程 开始测试,前 5 个请求出现错误。 测试通过我们的前端,它使用 cxf 客户端来访问后端的 camel/cxf 服务。

直接点击 camel/cxf 服务不会导致任何问题。

环境测试更新

我们还有 2 个在 Linux 上运行的其他环境,都在 JDK 1.7.0u60 上,相同版本的 glassfish 没有表现出这种行为。所有受影响的机器都仅限 OS X。 (不久将测试一个 Windows 框)

【问题讨论】:

    标签: java multithreading spring cxf apache-camel


    【解决方案1】:

    在对我能够测试的较小样本进行一些隔离和测试后,发现了问题。

    使用较小的应用程序进行测试,我能够部署到本地执行不同的服务器,并且一切正常。甚至尝试将服务部署到 Tomcat 和 Glassfish 上的前端,仍然没有问题。

    一旦我将前端和后端放在同一台服务器上,如果我同时发送 5 个请求,它就会卡住。我也尝试使用 JAX-WS 生成(而不是 CXF)服务,但它们也有同样的问题,排除了 CXF 特定问题的问题。

    根本问题

    Glassfish 的默认 http 线程池最大为 5。所以,只要我们尝试同时执行 5 个或更多请求....blamo!从技术上讲,如果我们尝试 5 次请求,我们实际上是在对资源执行 10. 5 次,然后资源会自己向后端执行 5 次。

    解决方案

    有几件事可以解决这个问题。增加 glassfish 中的线程池大小。无论如何,5似乎很小,所以无论如何都需要调整。

    另一个是简单地将两个应用程序放在不同的服务器上,这将是无论如何配置生产的方式,但可能会增加本地开发的大量开销。

    悬而未决的问题

    唯一未知的是,为什么我们在 linux qa/dev 环境中看不到这个。与它们的不同之处在于它们前面有 apache,而我们的本地实例没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-31
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多