1

spring 3.2.0.RELEASE resttemplate および httpcomponents 4.2.3 を使用して、rest 呼び出しを行います。メモリフットプリントは、最大に達するまで着実に増加しています。

構成は次のとおりです。

<bean id="myRestTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg>
        <bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
            <constructor-arg index="0">
                <bean factory-bean="httpClient" factory-method="get"/>
            </constructor-arg>
        </bean>
    </constructor-arg>
</bean>
<bean id="httpClient" class="com.mycompany.myproject.common.rest.HttpClient">
    <constructor-arg index="0" ref="myKeyserverCA" ></constructor-arg>
    <constructor-arg index="1" value="${com.mycompany.myproject.security.client.keyPassword}" ></constructor-arg>
    <constructor-arg index="2" value="${default.max.total.connections}" ></constructor-arg>
    <constructor-arg index="3" value="${default.max.host.connections}" ></constructor-arg>
</bean>
<bean id="myKeyserverCA"
      class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
    <property name="location" value="classpath:${com.mycompany.myproject.security.client.keyStore}" />
    <property name="password" value="${com.mycompany.myproject.security.client.keyStorePass}" />
</bean>    

Http クライアント:

import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.security.KeyStore;

public class HttpClient {

private static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = (60 * 1000);

private KeyStore keystore;
private String password;
private int MAX_TOTAL_CONNECTION;
private int MAX_PER_ROUTE;

public HttpClient(KeyStore keyStore, String keyPassword, int MAX_TOTAL_CONNECTION, int MAX_PER_ROUTE) {
    this.keystore = keyStore;
    this.password = keyPassword;
    this.MAX_TOTAL_CONNECTION = MAX_TOTAL_CONNECTION;
    this.MAX_PER_ROUTE = MAX_PER_ROUTE;
}

public org.apache.http.client.HttpClient get() {
    PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(getSchemeRegistry(this.keystore, this.password));
    connectionManager.setMaxTotal(MAX_TOTAL_CONNECTION);
    connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);
    connectionManager.closeExpiredConnections();

    org.apache.http.client.HttpClient httpClient = new DefaultHttpClient(connectionManager);
    httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, DEFAULT_READ_TIMEOUT_MILLISECONDS);
    return httpClient;
}

private static SchemeRegistry getSchemeRegistry(KeyStore keyStore, String keyPassword) {
    SchemeRegistry registry = new SchemeRegistry();
    try{
        TrustManager[] trustManagerArray = { new TautologicalX509TrustManager() };
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, keyPassword.toCharArray());

        SSLContext sslc = SSLContext.getInstance("TLS");
        sslc.init(kmf.getKeyManagers(), trustManagerArray, null);
                    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(sslc, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
                    registry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
        registry.register(new Scheme("https", 443, sslSocketFactory));
        return registry;
    }catch(Exception e){
        throw new RuntimeException(e.getMessage());
    }
}
}    

TautologicalX509TrustManager:

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class TautologicalX509TrustManager  implements X509TrustManager {

private static final X509Certificate[] EMPTY_CERTIFICATES = new X509Certificate [0];

public void checkClientTrusted(X509Certificate[] arg0, String arg1)
    throws CertificateException {
}

public void checkServerTrusted(X509Certificate[] arg0, String arg1)
        throws CertificateException {
}

public X509Certificate[] getAcceptedIssuers() {
    return EMPTY_CERTIFICATES;
}



}    

このコンポーネントで負荷テストを実行すると、多数の SSLSocketImpl オブジェクトと byte[] が表示されます。SSLSocketImpl への着信参照は、Finalizer オブジェクトからのものです。

負荷テストの停止後にマシンで netstat を実行すると、基礎となるサービスへの開いている TCP 接続が表示されません。ただし、負荷テスト中は、TIME_WAIT 状態の接続が多く、ESTABLISHED 状態の接続はほとんどありませんが、テストが停止するとすべてが閉じられます。

ソケットを閉じるための API 呼び出しが不足していませんか? ヒープ内に非常に多くの SSLSocketImpl オブジェクトがぶら下がっているのはなぜですか?

4

1 に答える 1

0

少し遅い返信ですが、この回答はこの質問への将来の訪問者向けです。大量のSSLSocketImplがヒープに表示され、ガベージ コレクションが行われる理由SSLSessionContextは、SSL 接続のキャッシングをサポートしているためです。これは、実際の TCP 接続が確立された後に一時的な暗号化キーをネゴシエートするときにハンドシェイク オーバーヘッドを削減するために、個別の TCP 接続間で再利用できます。 .

デフォルトではSSLSessionContext、24 時間のデフォルト期間に対して無制限の数のセッションが設定されています。つまり、大量のトラフィックが発生すると、最終的に大量のヒープ メモリを使用することになります。1 つの方法は、アプリケーションのニーズに合ったキャッシュ サイズを設定することです。以下に例を示します。

sslContext.getServerSessionContext().setSessionCacheSize(1000);

于 2016-07-08T01:39:53.800 に答える