Spring Rest Template с использованием Http Client показывает высокое время отклика во время тестирования производительности - PullRequest
0 голосов
/ 16 апреля 2020

Я создал загрузочное приложение Spring, которое вызывает REST API с помощью Rest Template. Сначала я использовал только компонент Rest Template, и время отклика дельты между основным приложением и оболочкой во время теста производительности составляло всего около 5-10 мс.

Чтобы иметь больше контроля над параллелизмом и HTTP соединений мы решили использовать httpclient-4.5.10 jar и использовали CloseableHttpClient для создания компонента Rest Template Bean. Тем не менее, после реализации этого мы заметили всплеск в среднем. время реакции дельты более 82 мс После тщательного анализа мы выяснили, что CommonsHttp[app-name]: execute занимает около 81,4 мс. Это означает, что HTTP-клиент отвечает за более высокое время отклика. Мы попробовали несколько способов настройки производительности, изменив стратегию поддержки активности, количество потоков и т. Д. c., Но ни один из них, похоже, не работает.

Вот конфигурация клиента Http:

// Determines the timeout in milliseconds until a connection is established.
@Value("${http-client.connect-timeout}")
private int connectTimeout;

// The timeout when requesting a connection from the connection manager.
@Value("${http-client.request-timeout}")
private int requestTimeout;

// The timeout for waiting for data
@Value("${http-client.socket-timeout}")
private int socketTimeout;

@Value("${http-client.max-total-connections}")
private int maxTotalConnections;

@Value("${http-client.default-max-per-route}")
private int defaultMaxPerRoute;

@Value("${http-client.default-keep-alive-time}")
private int defaultKeepAliveTime;

@Value("${http-client.close-idle-connection-wait-time}")
private int closeIdleConnectionWaitTime;

@Bean
public PoolingHttpClientConnectionManager poolingConnectionManager() {
    SSLContextBuilder builder = new SSLContextBuilder();
    try {
        builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
    } catch (NoSuchAlgorithmException | KeyStoreException e) {
        log.error("Pooling Connection Manager Initialisation failure because of {}", e.getMessage());
    }

    SSLConnectionSocketFactory sslsf = null;
    try {
        sslsf = new SSLConnectionSocketFactory(builder.build());
    } catch (KeyManagementException | NoSuchAlgorithmException e) {
        log.error("Pooling Connection Manager Initialisation failure because of {}", e.getMessage());
    }

    Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
            .<ConnectionSocketFactory>create().register("https", sslsf)
            .register("http", new PlainConnectionSocketFactory())
            .build();

    PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
    poolingConnectionManager.setMaxTotal(maxTotalConnections);
    poolingConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
    return poolingConnectionManager;
}

@Bean
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
    return new ConnectionKeepAliveStrategy() {
        @Override
        public long getKeepAliveDuration(HttpResponse response, HttpContext 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 defaultKeepAliveTime;
        }
    };
}

@Bean
public CloseableHttpClient httpClient() {
    RequestConfig requestConfig = RequestConfig.custom()
            .setConnectionRequestTimeout(requestTimeout)
            .setConnectTimeout(connectTimeout)
            .setSocketTimeout(socketTimeout).build();

    return HttpClients.custom()
            .setDefaultRequestConfig(requestConfig)
            .setConnectionManager(poolingConnectionManager())
            .setKeepAliveStrategy(connectionKeepAliveStrategy())
            .build();
}

@Bean
public Runnable idleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager) {
    return new Runnable() {
        @Override
        @Scheduled(fixedDelay = 10000)
        public void run() {
            try {
                if (connectionManager != null) {
                    log.trace("run IdleConnectionMonitor - Closing expired and idle connections...");
                    connectionManager.closeExpiredConnections();
                    connectionManager.closeIdleConnections(closeIdleConnectionWaitTime, TimeUnit.MILLISECONDS);
                } else {
                    log.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
                }
            } catch (Exception e) {
                log.error("run IdleConnectionMonitor - Exception occurred. msg={}, e={}", e.getMessage(), e);
            }
        }
    };
}

Конфигурация шаблона отдыха:

@Autowired
    CloseableHttpClient httpClient;

    @Bean
    public RestTemplate getRestTemplate(RestTemplateRequestResponseLoggingInterceptor loggingInterceptor) {
        ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(clientHttpRequestFactory());
        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.setInterceptors(Collections.singletonList(loggingInterceptor));
        return restTemplate;
    }

    @Bean
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setHttpClient(httpClient);
        return clientHttpRequestFactory;
    }

Свойства приложения:

# HTTP Client configs
http-client.connect-timeout: 2000
http-client.request-timeout: 5000
http-client.socket-timeout: 5000
http-client.max-total-connections: 200
http-client.default-max-per-route: 50
http-client.default-keep-alive-time: 300000
http-client.close-idle-connection-wait-time: 480000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...