生产环境中 Apache Http 客户端 4.5.11 配置的最佳实践



下面是我的ApacheHttpClient春豆,我想知道我的配置是否适合生产,或者我需要调整任何配置?有人可以分享一些信息,如果你在生产中使用最新的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");
}
}   

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

要评估的一些项目包括:

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

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

来自 Apache 的默认值可能是很好的默认值。Apache基金会和协助它的工程师经验丰富,并对这些默认值进行了思考。

(非官方(Apache HttpClient 5.0 迁移指南中有一节介绍了Apache HttpClient 4.5.x 版本的推荐配置参数和良好实践。

https://ok2c.github.io/httpclient-migration-guide/preparation.html

两个最重要的建议:

  • 始终重复使用 CloseableHttpClient 实例。它们的创建成本很高,但它们也是完全线程安全的,因此多个线程可以使用同一个 CloseableHttpClient 实例同时执行多个请求,从而充分利用持久连接重用和连接池。

  • 直接从内容流中使用响应内容,并将其转换为更高级别的对象,而不将其转换为中间字符串或字节数组。

事实证明,requestRetry值大于0会导致生产环境中SocketException,因此我们设置了requestRetry = 0并且没有收到任何SocketException异常

最新更新