[java] Apache HttpClient를 사용하여 웹 서버에 동시에 요청을 보낼 때 성능 최적화하기

Apache HttpClient는 Java에서 HTTP 요청을 보내는 데 사용되는 인기 있는 라이브러리입니다. 웹 서버에 동시에 여러 요청을 보내야 하는 상황에서 HttpClient를 사용하여 성능을 최적화하는 방법에 대해 알아보겠습니다.

1. HTTP Keep-Alive를 사용하십시오

기본적으로 HttpClient는 Keep-Alive 기능이 활성화되어 있어 HTTP 연결을 재사용할 수 있습니다. 이는 동시에 여러 요청을 보낼 때 연결을 매번 새로 만들지 않고 연결을 재사용하여 성능을 향상시킵니다.

CloseableHttpClient httpClient = HttpClients.createDefault();

2. Connection Pool 설정하기

HttpClient는 기본적으로 Connection Pool 기능을 지원합니다. 기본적으로 최대 20개의 연결을 관리하며, 이는 동시에 여러 요청을 처리할 수 있도록 해줍니다. 그러나 이 값을 늘리는 것이 성능 향상에 도움이 될 수 있습니다.

PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
connManager.setMaxTotal(200); // 최대 200개의 연결을 관리합니다.
connManager.setDefaultMaxPerRoute(100); // 동일한 호스트당 최대 100개의 연결을 허용합니다.

CloseableHttpClient httpClient = HttpClients.custom()
        .setConnectionManager(connManager)
        .build();

3. 요청별 Timeout 설정하기

HttpClient는 다양한 종류의 Timeout 설정을 지원합니다. 예를 들어, Connection Timeout은 연결을 설정하는 데 걸리는 시간을 제한하고, Socket Timeout은 응답을 기다리는 시간을 제한합니다. 이러한 Timeout 설정을 적절하게 조정하여 동시에 여러 요청을 보낼 때의 성능을 향상시키는 것이 중요합니다.

RequestConfig requestConfig = RequestConfig.custom()
    .setConnectTimeout(5000) // 5초 이내에 연결을 설정할 수 없는 경우 Timeout 발생
    .setSocketTimeout(5000) // 5초 이내에 응답을 받지 못하는 경우 Timeout 발생
    .build();

HttpGet httpGet = new HttpGet("http://example.com");
httpGet.setConfig(requestConfig);

CloseableHttpClient httpClient = HttpClients.createDefault();

4. 멀티스레드 환경에서 사용하기

HttpClient는 멀티스레드 환경에서 안전하게 사용될 수 있도록 설계되었습니다. 따라서 동시에 여러 요청을 보내는 경우에도 여러 스레드에서 동일한 HttpClient 인스턴스를 공유하여 사용할 수 있습니다.

CloseableHttpClient httpClient = HttpClients.createDefault();

ExecutorService executorService = Executors.newFixedThreadPool(10); // 10개의 스레드 풀 생성

List<CompletableFuture<Void>> futures = new ArrayList<>();

for (int i = 0; i < 10; i++) {
    int requestId = i;
    HttpGet httpGet = new HttpGet("http://example.com/api/" + requestId);

    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            // 응답 처리 로직 작성
            System.out.println("Request " + requestId + " completed with status " + response.getStatusLine().getStatusCode());
        } catch (IOException e) {
            // 예외 처리 로직 작성
        }
    }, executorService);

    futures.add(future);
}

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

위의 예제에서는 10개의 스레드를 사용하여 10개의 동시 요청을 보냅니다. CompletableFuture를 사용하여 각각의 응답을 비동기적으로 처리합니다.

위의 방법들을 적절히 조합하여 HttpClient를 사용할 때의 성능을 최적화하는 것이 중요합니다. 실제 상황에 맞게 설정을 조정하고, 테스트와 모니터링을 통해 성능을 계속 개선해나가는 것이 좋습니다.

참고 자료: