当前位置: 首页 > 知识库问答 >
问题:

PooledCloseableHttpClient影响性能吞吐量

杨腾
2023-03-14

我一直在使用SpringIntegration调用RESTAPI,但是SpringIntegration默认附带的http客户端不支持连接池或可重用性,因此我定制了使用PoolighttpClientConnectionManager

但是现在Spring集成停止在我的类路径中拾取JKS文件,所以我构建了自己的SSL上下文,但是构建这个SSL上下文导致了性能的显著下降

对于100个并发线程,

  1. 使用http客户端,我获得了200个TPS
  2. 使用PoollightTPClientConnectionManager和SSLConnectionSocketFactory。允许所有主机名验证,我得到了380 TPS
  3. 从JKS buildSslContext()构建SSL上下文我得到的TPS不到30个:(

上下文xml

<int:gateway id="ServiceRequestGateway"
             service-interface="com.company.security.integration.RequestGateway"
             default-request-channel="RequestChannel"
             default-reply-channel="ResponseChannel">
    <int:default-header name="Accept" value="application/json; v=5"/>
    <int:default-header name="Content-Type" value="application/json; v=5"/>
    <int:default-header name="ServiceType" expression="#args[1]"/>
</int:gateway>

<int-http:outbound-gateway
        id="Outbound_Gateway"
        request-channel="RequestChannel"
        reply-channel="ResponseChannel"
        request-factory="requestFactory"
        header-mapper="headerMapper"
        url="${service.host}/{xyzServiceType}"
        http-method="POST"
        expected-response-type="java.lang.String"
        extract-request-payload="true">
    <int-http:uri-variable name="ServiceType" expression="headers['xyzServiceType']" />
</int-http:outbound-gateway>

<!--Connection Pooling/Keep Alive/Retry-->
<bean id="httpClient" class="com.capitalone.security.config.PooledCloseableHttpClient">
</bean>

<bean id="requestFactory"
    class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
    <constructor-arg ref="httpClient"/>
    <property name="connectTimeout" value="5000"/>
    <property name="readTimeout"    value="5000"/>
</bean>

PooledCloseableHttpClient

public class PooledCloseableHttpClient implements FactoryBean {

@Autowired
S3ClientUtil s3Client;

// For TLS/SSL connectivity from this client to service
@Value("${jks.filename}")
String jksFile;

// Password for Java keystores
@Value("${keystore.password}")
String keystorePassword;

private int maxRetries = 2;
//1 second
@Value("${rest.call.request.retryInterval:1000}")
private int retryInterval = 1000;

@Value("${rest.call.request.keepAliveTime:60}")
private int keepAliveTime = 60;

@Value("${rest.call.request.maxConnection:200}")
private int maxConnection = 200;

@Value("${rest.call.request.maxConnectionsPerRoute:100}")
private int maxConnectionsPerRoute = 100 ;

SSLConnectionSocketFactory sslConnectionSocketFactory;

// Custom Keep-Alive
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> {
    HeaderElementIterator it = new BasicHeaderElementIterator
            (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
    while (it.hasNext()) {
        HeaderElement he = it.nextElement();
        String param = he.getName();
        String value = he.getValue();
        if (value != null && param.equalsIgnoreCase
                ("timeout")) {
            return Long.parseLong(value) * 1000;
        }
    }
    return keepAliveTime * 1000;
};

// Called once during initialization to get JKS file from Cloud
private SSLContext buildSslContext() {
    try {
        // Get the JKS contents and then use the pooling connection manager below
        File keyStoreFile = s3Client.importKeystoreFile(jksFile);

        // Build key store from JKS file downloaded from S3
        final KeyStore keyStore = KeyStore.getInstance("JKS");
        InputStream is = null;
        try {
            is = new FileInputStream(keyStoreFile); // Get Keystore
            keyStore.load(is, keystorePassword.toCharArray()); //Get keystore password
        } finally {
            IOUtils.closeQuietly(is);
        }

        // Build SSL Context
        SSLContextBuilder sslBuilder = new SSLContextBuilder();
        sslBuilder.loadKeyMaterial(keyStore, keystorePassword.toCharArray());
        sslBuilder.loadTrustMaterial(keyStoreFile, keystorePassword.toCharArray());

        return sslBuilder.build();
    } catch (final GeneralSecurityException | IOException exc) {
        return null;
    }
}

@Override
public Object getObject() throws Exception {

    //Build PoolingHttpClientConnectionManager
    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(
            RegistryBuilder.<ConnectionSocketFactory> create()
                    .register("https", new SSLConnectionSocketFactory(buildSslContext(), new NoopHostnameVerifier()))
                    .register("http", new PlainConnectionSocketFactory()).build());

    // Build HttpClient
    HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties().setConnectionManager(poolingConnectionManager)
            .setKeepAliveStrategy(keepAliveStrategy)
            .setSSLSocketFactory(sslConnectionSocketFactory)
            .setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy(maxRetries, retryInterval));
    return httpClientBuilder.build();
}

@Override
public Class<?> getObjectType() {
    return CloseableHttpClient.class;
}

@Override
public boolean isSingleton() {
    return true;
}

}

共有1个答案

穆飞星
2023-03-14

下面是重构后的HttpClient类,它为我提供了最佳性能。

public class PooledCloseableHttpClient implements FactoryBean {

@Autowired
S3ClientUtil s3Client;

// For TLS/SSL connectivity from this client to service
@Value("${jks.filename}")
String jksFile;

// Password for Java keystores
@Value("${keystore.password}")
String keystorePassword;

private int maxRetries = 2;
//1 second
@Value("${rest.call.request.retryInterval:1000}")
private int retryInterval = 1000;

@Value("${rest.call.request.keepAliveTime:60}")
private int keepAliveTime = 60;

@Value("${rest.call.request.maxConnection:200}")
private int maxConnection = 200;

@Value("${rest.call.request.maxConnectionsPerRoute:100}")
private int maxConnectionsPerRoute = 100 ;

SSLConnectionSocketFactory sslConnectionSocketFactory;

// Custom Keep-Alive
ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> {
    HeaderElementIterator it = new BasicHeaderElementIterator
            (response.headerIterator(HTTP.CONN_KEEP_ALIVE));
    while (it.hasNext()) {
        HeaderElement he = it.nextElement();
        String param = he.getName();
        String value = he.getValue();
        if (value != null && param.equalsIgnoreCase
                ("timeout")) {
            return Long.parseLong(value) * 1000;
        }
    }
    return keepAliveTime * 1000;
};

// Called once during initialization to get JKS file from Cloud
private SSLContext buildSslContext() {
    try {
        // Get the JKS contents and then use the pooling connection manager below
        File keyStoreFile = s3Client.importKeystoreFile(jksFile);

        // Build key store from JKS file downloaded from S3
        final KeyStore keyStore = KeyStore.getInstance("JKS");
        InputStream is = null;
        try {
            is = new FileInputStream(keyStoreFile); // Get Keystore
            keyStore.load(is, keystorePassword.toCharArray()); //Get keystore password
        } finally {
            IOUtils.closeQuietly(is);
        }

        // Build SSL Context
        SSLContextBuilder sslBuilder = new SSLContextBuilder();
        sslBuilder.loadKeyMaterial(keyStore, keystorePassword.toCharArray());
        sslBuilder.loadTrustMaterial(keyStoreFile, keystorePassword.toCharArray());

        return sslBuilder.build();
    } catch (final GeneralSecurityException | IOException exc) {
        return null;
    }
}

@Override
public Object getObject() throws Exception {

    //Build PoolingHttpClientConnectionManager
    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(
            RegistryBuilder.<ConnectionSocketFactory> create()
                    .register("https", new SSLConnectionSocketFactory(buildSslContext(), new NoopHostnameVerifier()))
                    .register("http", new PlainConnectionSocketFactory()).build())
        poolingConnectionManager.setMaxTotal(maxConnection);
        poolingConnectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

    // Build HttpClient
    HttpClientBuilder httpClientBuilder = HttpClients.custom().useSystemProperties().setConnectionManager(poolingConnectionManager)
                .setKeepAliveStrategy(keepAliveStrategy)
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setConnectionReuseStrategy((arg0, arg1) -> true)
                .setMaxConnTotal(maxConnection)
                .setMaxConnPerRoute(maxConnectionsPerRoute)
                .setServiceUnavailableRetryStrategy(new ServiceUnavailableRetryStrategy(maxRetries, retryInterval));
    return httpClientBuilder.build();
}

@Override
public Class<?> getObjectType() {
    return CloseableHttpClient.class;
}

@Override
public boolean isSingleton() {
    return true;
}
}
 类似资料:
  • 我有一个主机名列表,我应该通过使用正确的URL来打电话。假设我在链表中有四个主机名(hostA,hostB,hostC,hostD)- 执行hostA url,如果hostA启动,则获取数据并返回响应 此外,我的应用程序中运行了一个后台线程,其中包含阻止主机名列表(来自我的另一个服务),我们不应该调用该列表,但它每10分钟运行一次,因此阻止主机名列表只会在10分钟后更新,因此如果存在任何阻止主机名

  • 问题内容: 我知道这是一个非常笼统的问题。但是,我想了解使Redis(或诸如MemCached,Cassandra之类的缓存)在惊人的性能极限下工作的主要架构决策是什么。 如何维护连接? 连接是TCP还是HTTP? 我知道它完全用C编写。如何管理内存? 尽管存在竞争的读/写,但用于实现高吞吐量的同步技术有哪些? 基本上,具有内存高速缓存的计算机和可以响应命令的服务器的普通香草实现和Redis框之间

  • 来自Kafka文献 当制作人将ACK设置为“all”(或“-1”)时,此min.insync。副本配置指定必须确认写入才能被视为成功写入的最小副本数。 它表示当同步副本的最小数量确认时,写入成功,但当我使用为1和3(对于5个代理设置中的分区=1和R.F=5的主题),带有的kafka producer的性能是相同的。 所以,每主题配置会影响Kafka producer的吞吐量(独立运行)和?

  • 我对193个示例运行了一个JMeter测试,平均响应时间为5915ms,Throghput为1.19832。 我只想知道它们到底有什么关系

  • 来自AWS Lambda常见问题解答: Q: 我一次可以执行的AWS Lambda函数的数量是否有限制? 不需要。AWS Lambda旨在并行运行多个函数实例。然而,AWS Lambda的默认安全限制为每个区域每个帐户100次并发执行。如果您希望提交请求以增加100次并发执行的限制,您可以访问我们的支持中心,单击“打开新案例”,然后提交服务限制增加请求。 Q: 如果我的帐户超过并发执行的默认限制,

  • 在大数据存储中,IOPS和吞吐量之间的关键区别是什么