Apache AsyncHttpClient 4.1.4 создание нового сокетного соединения вместо повторного использования соединения из пула соединений - PullRequest
1 голос
/ 31 марта 2020

Мы используем Apache AsyncHttpClient с зависимостями ниже

[INFO] +- org.apache.httpcomponents:httpasyncclient:jar:4.1.4:compile
[INFO] |  +- org.apache.httpcomponents:httpcore:jar:4.4.10:compile
[INFO] |  +- org.apache.httpcomponents:httpcore-nio:jar:4.4.10:compile
[INFO] |  \- org.apache.httpcomponents:httpclient:jar:4.5.6:compile

Мы замечаем, что это создает новое соединение с сокетом с нисходящим потоком (с включенной аутентификацией ssl и клиента) для каждого запроса. Мы ожидаем повторного использования соединения из пула.

Ниже приведены журналы отладки

2020:03:31:19:49:27.430 DEBUG I/O dispatcher 8 ManagedNHttpClientConnectionImpl  http-outgoing-55 127.0.0.1:51706<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.430 DEBUG I/O dispatcher 9 ManagedNHttpClientConnectionImpl  http-outgoing-56 127.0.0.1:51740<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.534 DEBUG I/O dispatcher 10 ManagedNHttpClientConnectionImpl  http-outgoing-57 127.0.0.1:51741<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.637 DEBUG I/O dispatcher 11 ManagedNHttpClientConnectionImpl  http-outgoing-58 127.0.0.1:51742<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.740 DEBUG I/O dispatcher 12 ManagedNHttpClientConnectionImpl  http-outgoing-59 127.0.0.1:51743<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.840 DEBUG I/O dispatcher 13 ManagedNHttpClientConnectionImpl  http-outgoing-60 127.0.0.1:51744<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:32.938 DEBUG I/O dispatcher 14 ManagedNHttpClientConnectionImpl  http-outgoing-61 127.0.0.1:51745<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.041 DEBUG I/O dispatcher 15 ManagedNHttpClientConnectionImpl  http-outgoing-62 127.0.0.1:51746<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.146 DEBUG I/O dispatcher 16 ManagedNHttpClientConnectionImpl  http-outgoing-63 127.0.0.1:51747<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.238 DEBUG I/O dispatcher 1 ManagedNHttpClientConnectionImpl  http-outgoing-64 127.0.0.1:51748<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.344 DEBUG I/O dispatcher 2 ManagedNHttpClientConnectionImpl  http-outgoing-65 127.0.0.1:51749<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.432 DEBUG I/O dispatcher 3 ManagedNHttpClientConnectionImpl  http-outgoing-66 127.0.0.1:51750<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.541 DEBUG I/O dispatcher 4 ManagedNHttpClientConnectionImpl  http-outgoing-67 127.0.0.1:51751<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.638 DEBUG I/O dispatcher 5 ManagedNHttpClientConnectionImpl  http-outgoing-68 127.0.0.1:51752<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500
2020:03:31:19:51:33.743 DEBUG I/O dispatcher 6 ManagedNHttpClientConnectionImpl  http-outgoing-69 127.0.0.1:51753<->127.0.0.1:8102[ACTIVE][rw:][ACTIVE][rw][NEED_UNWRAP][0][0][239]: Set timeout 500

Примечание. При использовании без SSL оно работает в соответствии с нашими ожиданиями (повторное использование соединения из пула )

Ниже приведены наши конфиги

      "sslEnabled": true,
      "host": "127.0.0.1",
      "port": 8102,
      "staleConnectionMonitorThreadName": "http-stale-connection-cleaner-thread",
      "publishMaxThreadPoolSize": 1,
      "defaultMaxThreadsPerRoute": 1,
      "maxThreadsPerRoute": 1,
      "connectionRequestTimeoutMs": 500,
      "connectionTimeoutMs": 500,
      "socketTimeoutMs": 500,
      "evictThreadSleepTimeMs" : 5000,
      "maxKeepAliveTimeMs" : 30000,
      "trustStorePath": "abc.jks",
      "trustStoreKey": "**",
      "keyStorePath": "xyx.jks",
      "keyStoreKey": "**"

Ниже приведены заголовки запросов

Content-Type: application/json
v-c-correlation-id: f7e046a9-e1f1-44f1-9fb4-dddcb973a951
v-c-username: xyz
Content-Length: 218
Host: 127.0.0.1:8102
Connection: Keep-Alive
User-Agent: Apache-HttpAsyncClient/4.1.4 (Java/1.8.0_201)

Ниже приведены заголовки ответов

"HTTP/1.1 200 OK[\r][\n]"
"Content-Type: application/json[\r][\n]"
"v-c-correlation-id: f7e046a9-e1f1-44f1-9fb4-dddcb973a951[\r][\n]"
"Content-Length: 0[\r][\n]"

Примечание: версия jdk 1,8

1 Ответ

1 голос
/ 01 апреля 2020

Apache HttpClient различает так называемые соединения без состояния и с состоянием. Соединения с отслеживанием состояния - это те, которые создаются с определенной идентификацией пользователя или контекстом безопасности. HttpClient версий 4.x и 5.x по умолчанию поддерживает два типа: соединения с аутентификацией NTLM и соединения TLS с аутентификацией клиента. Соединения с состоянием, хотя и могут быть использованы повторно, считаются чувствительными. Диспетчер пула соединений не будет сдавать в аренду эти соединения, если токен пользователя в контексте выполнения HTTP не совпадет с тем, что состояние соединения сохраняется в пуле.

  1. Один выполняет несколько запросов в одном и том же контекст выполнения и, таким образом, заставить их использовать один и тот же идентификатор пользователя. ВАЖНО : HttpContext экземпляры НЕ ДОЛЖНЫ использоваться одновременно! Некоторые атрибуты, хранящиеся в HttpContext, не являются многопоточными!

    CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
    try {
        httpclient.start();
        HttpClientContext clientContext = HttpClientContext.create();
        HttpGet request1 = new HttpGet("http://httpbin.org/get");
        Future<HttpResponse> future1 = httpclient.execute(request1, clientContext, null);
        HttpResponse response1 = future1.get();
        System.out.println("Response: " + response1.getStatusLine());
        HttpGet request2 = new HttpGet("http://httpbin.org/get");
        Future<HttpResponse> future2 = httpclient.execute(request2, clientContext, null);
        HttpResponse response2 = future2.get();
        System.out.println("Response: " + response2.getStatusLine());
    } finally {
        System.out.println("Shutting down");
        httpclient.close();
    }
    
  2. Использовать разные HttpContext экземпляры для связанных запросов, но вручную назначать этим запросам один и тот же пользовательский токен

    CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
    try {
        httpclient.start();
        HttpClientContext clientContext1 = HttpClientContext.create();
        clientContext1.setUserToken("appuser");
        HttpGet request1 = new HttpGet("http://httpbin.org/get");
        Future<HttpResponse> future1 = httpclient.execute(request1, clientContext1, null);
        HttpResponse response1 = future1.get();
        System.out.println("Response: " + response1.getStatusLine());
        HttpClientContext clientContext2 = HttpClientContext.create();
        clientContext2.setUserToken("appuser");
        HttpGet request2 = new HttpGet("http://httpbin.org/get");
        Future<HttpResponse> future2 = httpclient.execute(request2, clientContext2, null);
        HttpResponse response2 = future2.get();
        System.out.println("Response: " + response2.getStatusLine());
    } finally {
        System.out.println("Shutting down");
        httpclient.close();
    }
    
  3. Если конечная точка клиента не поддерживает разные пользовательские идентификаторы (существует общий контекст безопасности, общий для всех HTTP-запросов), можно просто отключить управление состоянием соединения

    CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
            .disableConnectionState()
            .build();
    
...