首页 > 解决方案 > Apache Http Client 4.5.11 生产环境配置最佳实践

问题描述

下面是我的ApacheHttpClientSpring bean,我想知道我的配置是否适合生产,或者我是否需要调整任何配置?如果您在生产中使用最新的 Apache Http 客户端,有人可以分享一些信息吗

@Service
public class ApacheHttpClient implements IHttpClient {
    private static final Logger              LOGGER                                             = Logger
            .getInstance(ApacheHttpClient.class);
    private static final int                 DEFAULT_MAX_TOTAL_CONNECTIONS                      = 400;
    private static final int                 DEFAULT_IDLE_CONNECTION_EVICTION_FREQUENCY_SECONDS = 300;
    private static final int                 DEFAULT_MAX_CONNECTIONS_PER_ROUTE                  = DEFAULT_MAX_TOTAL_CONNECTIONS;

    private static final int                 DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS            = (60 * 1000);
    private static final int                 DEFAULT_READ_TIMEOUT_MILLISECONDS                  = (4 * 60 * 1000);
    private static final int                 DEFAULT_WAIT_TIMEOUT_MILLISECONDS                  = (60 * 1000);
    private static final int                 DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLISECONDS     = (5 * 60 * 1000);

    private static final int                 DEFAULT_KEEP_ALIVE_MILLISECONDS                    = (5 * 60 * 1000);
    private static final int                 DEFAULT_REQUEST_RETRY                              = 2;

    @Autowired
    private SSLContextHelper                 customSSLContext;

    private int                              keepAlive                                          = DEFAULT_KEEP_ALIVE_MILLISECONDS;
    private int                              maxTotalConnections                                = DEFAULT_MAX_TOTAL_CONNECTIONS;

    private int                              maxConnectionsPerRoute                             = DEFAULT_MAX_CONNECTIONS_PER_ROUTE;
    private int                              connectTimeout                                     = DEFAULT_CONNECTION_TIMEOUT_MILLISECONDS;
    private int                              readTimeout                                        = DEFAULT_READ_TIMEOUT_MILLISECONDS;

    private int                              waitTimeout                                        = DEFAULT_WAIT_TIMEOUT_MILLISECONDS;
    private int                              requestRetry                                       = DEFAULT_REQUEST_RETRY;

    private CloseableHttpClient              httpClient;

    private 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")) {
                                                                                                            try {
                                                                                                                return Long
                                                                                                                        .parseLong(
                                                                                                                                value)
                                                                                                                        * 1000;
                                                                                                            } catch (NumberFormatException ignore) {}
                                                                                                        }
                                                                                                    }
                                                                                                    return keepAlive;
                                                                                                };


    @PostConstruct
    public void initializeApacheHttpClient() {

        // config timeout
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(connectTimeout)
                .setConnectionRequestTimeout(waitTimeout)
                .setSocketTimeout(readTimeout).build();
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(customSSLContext.getSSLContext())).build();

        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

        connManager.setMaxTotal(maxTotalConnections);

        // Increase default max connection per route
        connManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);

        // Defines period of inactivity in milliseconds after which persistent connections must be re-validated prior to
        // being reused
        connManager.setValidateAfterInactivity(DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLISECONDS);

        httpClient = HttpClients.custom().setKeepAliveStrategy(keepAliveStrategy).setConnectionManager(connManager)
                .setConnectionManagerShared(true).setSSLContext(customSSLContext.getSSLContext())
                .setDefaultRequestConfig(config)
                .setRetryHandler(new DefaultHttpRequestRetryHandler(requestRetry, true))
                .build();

        // detect idle and expired connections and close them
        IdleConnectionEvictor staleMonitor = new IdleConnectionEvictor(connManager, DEFAULT_IDLE_CONNECTION_EVICTION_FREQUENCY_SECONDS);
        staleMonitor.start();

        LOGGER.log(Level.INFO, "Initialize ApacheHttpClient is successful");
    }
}   

标签: javaspringapache-httpclient-4.xapache-httpcomponents

解决方案


我不确定是否可以对这个问题给出明确的客观答案。没有适用于所有应用程序的单一设置集。您的生产环境和应用程序将是独一无二的。

一些要评估的项目是:

  • 设置与您的用户或上游调用者可以容忍的响应时间一致的超时
  • 设置与支持预期最大流量所需的连接数一致的连接限制
  • 设置适合您的应用程序的重试 - 您的应用程序会容忍重试,还是会因为重放请求而引发问题行为?

您还需要查看监控并观察连接、内存使用、响应时间、超时、错误等的日志和实时指标。

来自 Apache 的默认值可能是很好的默认值。Apache 基金会和为其提供协助的工程师经验丰富,并考虑到了这些默认设置。


推荐阅读