获取响应代码时出现文件描述符泄漏问题(cxf、ssl)

6

我们在生产环境中有一个问题已经存在了相当长的一段时间...

这是我之前提出的问题的跟进:(链接),但是这次更加具体,因此我认为将其发布为新问题是有道理的(如果不是,我会将此信息添加到其他问题中)。

以下是详细信息:

因此,我们在aix上使用(ibm) java 6 weblogic的应用程序中存在文件描述符泄漏,该应用程序使用cxf并且我们访问自己的web服务以及jsb,后者路由到我们的ws。

在weblogic启动时使用File Leak Detector作为代理,并转储getCurrentOpenFiles(),并在Listener.SocketRecord编程时进行过滤,我们有2000多个打开的套接字;

这些都是Java套接字和文件描述符,网络套接字(通过netstat查看)按时间正确关闭,但编程套接字(以及通过

lsof -p $pid_of_managed_server 2> /dev/null|grep TCP|wc -l

保持打开状态(最终会导致太多的打开文件问题)。

这是 jvm 中一个打开的文件描述符堆栈的头部:

record socket to tst-cjcsr.com/10.239.7.19:443 by thread:[ACTIVE] ExecuteThread: '0' for queue: 'weblogic.kernel.Default (self-tuning)' on Thu Nov 10 10:25:56 CET 2016
    at java.net.PlainSocketImpl.create(PlainSocketImpl.java:188)
    at java.net.Socket.createImpl(Socket.java:411)
    at java.net.Socket.connect(Socket.java:544)
    at weblogic.net.http.HttpsClient.openWrappedSSLSocket(HttpsClient.java:565)
    at weblogic.net.http.HttpsClient.openServer(HttpsClient.java:296)
    at weblogic.net.http.HttpsClient.openServer(HttpsClient.java:373)
    at weblogic.net.http.HttpsClient.New(HttpsClient.java:528)
    at weblogic.net.http.HttpsURLConnection.connect(HttpsURLConnection.java:239)
    at weblogic.net.http.HttpURLConnection.getInputStream(HttpURLConnection.java:409)
    at weblogic.net.http.SOAPHttpsURLConnection.getInputStream(SOAPHttpsURLConnection.java:37)
    at weblogic.net.http.HttpURLConnection.getResponseCode(HttpURLConnection.java:1038)
    at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:266)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1550)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1579)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1520)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1317)
    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:572)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:481)
    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:136)
    at com.sun.proxy.$Proxy380.requestOurRecord(Unknown Source)
    at some.package.application.dossier.DossierBean$1.call(DossierBean.java:225)

我可以想象这是一个应用问题,因为我在网上找不到其他类似缺陷的案例。
有人能从这个堆栈中更多地理解吗?
例如:HTTPConduit.close()想要创建连接让我感到奇怪...
另一点是:相同技术堆栈进行非HTTPS调用时不会出现此问题。(这是有道理的,因为堆栈跟踪提到了 Https Client)
CXF版本:2.7.18
cxf配置:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:soap="http://cxf.apache.org/bindings/soap"
       xmlns:cxf="http://cxf.apache.org/core"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>

    <context:property-placeholder location="file:${config.file.location}cjr-extract-${environment}.properties"/>

    <jaxws:client id="OurService"
                  serviceClass="some.package.ws.extract.generated.OurService"
                  address="${ws.extract.wsdl.endpoint}">
        <jaxws:binding>
            <soap:soapBinding version="1.2"/>
        </jaxws:binding>
    </jaxws:client>

    <cxf:bus>
        <cxf:outInterceptors>
            <bean class="our.package.interceptors.SomeInterceptor"
                  id="webSecurityInterceptor">
                <constructor-arg>
                    <map>
                        <entry key="action" value="Timestamp Signature"/>
                        <entry key="user" value="${org.apache.ws.security.crypto.merlin.keystore.alias}"/>
                        <entry key="passwordCallbackRef">
                            <ref bean="passwordCallBack"/>
                        </entry>
                        <!--entry key="signaturePropFile" value="properties/our.properties"/-->
                        <entry key="signaturePropFile" value="file:${location}/our.properties"/>
                        <entry key="signatureKeyIdentifier" value="DirectReference" />
                    </map>
                </constructor-arg>
            </bean>
        </cxf:outInterceptors>
        <cxf:properties>
            <entry key="signatureParts"
                   value="{Element}{http://www.w3.org/2003/05/soap-envelope}Body;{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp"/>
        </cxf:properties>
    </cxf:bus>

    <bean id="passwordCallBack" class="our.package.authentication.PasswordCallbackHandler">
        <property name="password" value="${password}"/>
        <property name="alias" value="${org.apache.ws.security.crypto.merlin.keystore.alias}"/>
    </bean>
</beans>

Java:

java version "1.6.0"
Java(TM) SE Runtime Environment (build pap3260sr15fp1-20140110_01(SR15 FP1))
IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 AIX ppc-32 jvmap3260sr15-
20131231_180656 (JIT enabled, AOT enabled)
J9VM - 20131231_180656
JIT  - r9_20130920_46510ifx3
GC   - GA24_Java6_SR15_20131231_1152_B180656)
JCL  - 20140107_01

Weblogic 10.3.6

感谢提示、指引和答案(如果可能的话);-)

S.

EJP 请求代码,以下是:

调用本身:

private OurService ourservice;

private Callable<RequestOurRecordResponse> callService(final RequestOurRecordRequest request) {
    return new Callable<RequestOurRecordResponse>() {
        @Override
        public RequestOurRecordResponse call() throws Exception {
            try {
                return ourService.requestOurRecord(request); // this is line 225.
            } catch (Exception e) {
                facesMessages.error("technicalError");
                log.error("Encountered technical error", e);
                return null;
            }
        }
    };
}

生成的Web服务:
package some.package.ws.extract.generated;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.xml.bind.annotation.XmlSeeAlso;


/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.1.7-b01-
 * Generated source version: 2.1
 * 
 */
@WebService(name = "OurService", targetNamespace = "http://secret/service-v1.0-rc2")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public interface OurService {
    /**
     * 
     * @param requestOurRecordRequest
     * @return
     *     returns some.package.ws.extract.generated.RequestOurRecordResponse
     */
    @WebMethod(action = "http://secret/service/RequestOurRecord")
    @WebResult(name = "requestOurRecordResponse", targetNamespace = "http://secret/service-v1.0-rc2", partName = "requestOurRecordResponse")
    public RequestOurRecordResponse requestOurRecord(
        @WebParam(name = "requestOurRecordRequest", targetNamespace = "http://secret/service-v1.0-rc2", partName = "requestOurRecordRequest")
        RequestOurRecordRequest requestOurRecordRequest);
}

使用:

<http-conf:conduit name="*.http-conduit">
    <http-conf:client Connection="Close" />
</http-conf:conduit>

这些连接(操作系统级别)已关闭,但我们仍然存在泄漏(如上所述的行为)。

使用:

<http-conf:conduit name="*.http-conduit">
    <http-conf:client Connection="Keep-Alive" />
</http-conf:conduit>

无论是连接(操作系统级别)还是文件描述符,都在不断增加...

(附加信息:操作系统级别的连接会下降(我猜是在超时后),但文件描述符仍然保持打开状态...)


@EJP 问题在于CXF的配置。这就是为什么没有代码的原因。我不能去粘贴CXF的代码:我们只是不知道内部发生了什么。你想要调用的代码?好的,没问题,几分钟内就能完成,但它不会给你更多的提示。 - Olivier Grégoire
@EJP:所有打开的文件描述符似乎都卡在java.net.PlainSocketImpl.create(PlainSocketImpl.java:188)上;我们可以在OpenJdk中搜索此代码,但在IBM中找不到(这导致了问题);此外,堆栈跟踪使用了很多Weblogic内部代码,这些代码由cxf调用,我们调用了它,但我们的代码仅限于Olivier提供的代码(以及我提供的配置)。 - SanThee
你尝试过使用超时吗?如果还没有检查,我发现了这个问题:https://dev59.com/SG035IYBdhLWcg3wC7gR#37605213 - HRgiger
感谢 @HRgiger,我们已经增加了打开文件的限制。这只是将问题推迟到以后,而且我们不能再增加太多。我们一定会检查 TIME_WAIT 设置。 - Olivier Grégoire
@HRgiger:我们已经做了:tcp_timewait(它是一台AIX机器)设置为1->这意味着15秒;泄漏的不是网络连接,而是与它们相关联的文件描述符;网络连接被正确关闭,但文件描述符仍然存在并增加...感谢您的建议... - SanThee
至少我尝试了:)他提到“套接字连接被视为文件并使用文件描述符,这是一种有限的资源”,所以我认为值得一试。 - HRgiger
1个回答

1
从我的角度来看,问题与cxf配置有关,也许weblogic + cxf的相互作用也是一个问题,因为正是cxf组件管理连接(请参见堆栈跟踪)。因此,我建议尝试不同的保持活动设置(如何设置保持活动,请参见这里)。但似乎这并没有帮助解决打开文件描述符的问题。
更新:
经过更深入地思考你的问题:
at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:266)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1550)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1579)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1520)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1317)

似乎在关闭http连接时,cxf尝试获取一些响应代码并为此创建套接字,由于这些套接字只是无限期地等待从未到来的响应,因此会导致泄漏。整个流程在一个简化的客户端工作流程部分here中描述。那么,下一个问题是,tst-cjcsr.just.fgov.be是否会回复?我的下一个建议是根据link中的说明为http-conf:client配置ReceiveTimeout

1
从我的角度来看,问题与cxf配置有关,也许weblogic和cxf的相互作用也是一个问题。通过将keep-alive设置为false,我希望cxf会明确地关闭套接字,从而释放文件描述符。而Bamboomy表示,如果我理解正确,以编程方式打开的套接字会保持打开状态。 - borowis
1
我理解你的意思,我会试一试并告诉你结果,这个明天早上就能完成;感谢你的建议(以及超前思考的想法 ;) ) - SanThee
1
我已经编辑了问题,无论是将“Keep-Alive”还是“close”作为“Connection”的值都存在问题... - SanThee
我们一直在努力让您的见解在我们的代码中发挥作用,以便在我无法再授予赏金之前实现,但目前还没有成功。 - Olivier Grégoire
@BorysZibrov:嘿,在我的原始问题中展示了调用Web服务的代码http://stackoverflow.com/questions/40401064/weblogic-doesnt-close-files-but-does-close-connections,但是调整ReceiveTimeout也不会有帮助,我认为;从文档中我读到默认的超时时间是60,000秒; 但是,文件描述符在60秒后不会关闭。 - SanThee
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接