Apache HttpClient를 사용할 때 커넥션 풀(Connection Pool) 설정은 성능과 안정성에 매우 중요한 요소입니다.
특히 아래 두 가지 옵션은 반드시 이해하고 사용하는 것이 좋습니다.
PoolingHttpClientConnectionManager connectionManager =
PoolingHttpClientConnectionManagerBuilder.create()
.setDefaultConnectionConfig(connectionConfig)
.setMaxConnTotal(maxConnections)
.setMaxConnPerRoute(Math.max(1, maxConnections / 3))
.build();
여기서 핵심은 다음 두 가지입니다.
maxConnTotal
= 전체 커넥션 풀의 최대 개수
maxConnPerRoute
= 특정 route 하나가 사용할 수 있는 최대 커넥션 개수
route란 무엇인가?
HttpClient에서 route는 일반적으로 다음 조합으로 구분됩니다.
- scheme + host + port
예를 들어 아래 대상들은 서로 다른 route입니다.
- https://api-a.example.com:443
- https://api-b.example.com:443
- http://api-a.example.com:80
즉 외부 API 서버가 10개라면 보통 route도 10개라고 이해하시면 됩니다.
maxConnTotal
maxConnTotal은 전체 커넥션 풀에서 동시에 유지할 수 있는 최대 커넥션 개수입니다.
예를 들어:
- setMaxConnTotal(100)
이라면 의미는 다음과 같습니다.
- 전체 route를 합쳐 최대 100개의 커넥션만 사용 가능
예시를 보면 이해가 쉽습니다.
route A: 20개
route B: 20개
route C: 20개
route D: 20개
route E: 20개합계: 100개
이 상태에서는 전체 커넥션 풀이 꽉 찬 상태입니다.
따라서 다른 route에 여유가 있더라도 새 커넥션을 생성할 수 없습니다.
maxConnPerRoute
maxConnPerRoute는 특정 route 하나가 사용할 수 있는 최대 커넥션 수입니다.
예를 들어:
- setMaxConnTotal(100)
- setMaxConnPerRoute(20)
이라면 의미는 다음과 같습니다.
전체 커넥션 최대: 100개
route 하나당 최대: 20개
즉 특정 서버 하나가 전체 커넥션을 독점하지 못하도록 제한하는 역할입니다.
많이 헷갈리는 부분
다음처럼 생각하시는 경우가 많습니다.
- route 10개 × route당 20개 = 200개
하지만 실제로 커넥션이 200개 생성되는 것은 아닙니다.
실제 전체 한도는 여전히
- maxConnTotal = 100
입니다.
즉 maxConnPerRoute는 보장량이 아니라 상한선(limit)입니다.
예시로 이해하기
1. 평상시 상황
조건:
- maxConnTotal = 100
- maxConnPerRoute = 20
- route = 10개
사용량:
route 1: 2개
route 2: 2개
...
route 10: 2개총 사용량: 20개
이 경우 아무 문제가 없습니다.
전체 100개 중 20개만 사용 중입니다.
2. 특정 route에 트래픽이 몰리는 경우
- route 1: 20개
- route 2~10: 각각 2개
이 경우 route 1은 이미 maxConnPerRoute = 20에 도달했습니다.
따라서
route 1의 21번째 요청은 대기
하게 됩니다.
하지만 전체 커넥션 수는 아직 100 미만이므로 다른 route들은 계속 커넥션을 사용할 수 있습니다.
3. 전체 풀이 꽉 찬 경우
route 1: 20개
route 2: 20개
route 3: 20개
route 4: 20개
route 5: 20개총합: 100개
이 경우:
- maxConnTotal = 100 도달
상태입니다.
따라서 route 6~10은 자기 route 제한은 남아있어도 새 커넥션을 생성할 수 없습니다.
maxConnPerRoute를 설정하지 않으면?
Apache HttpClient 5.x 기준으로 기본 route별 최대 커넥션 수는 일반적으로 5의 값을 가집니다.
예를 들어:
- setMaxConnTotal(100)
처럼 maxConnPerRoute를 생략하면 전체 커넥션은 100개까지 가능하지만 특정 서버 하나는 최대 5개 정도까지만 동시에 사용할 수 있습니다.
즉 특정 외부 API 서버에 요청이 몰리는 구조라면 병목이 발생할 수 있습니다.
maxConnections / 3 의 의미
다음 설정을 보겠습니다.
- setMaxConnPerRoute(Math.max(1, maxConnections / 3))
예를 들어:
- maxConnections = 90
이면:
- maxConnTotal = 90
- maxConnPerRoute = 30
이라는 의미입니다.
즉 특정 route 하나가 전체 커넥션의 1/3 이상 사용하지 못하도록 제한하는 것입니다.
이는 특정 서버가 전체 커넥션 풀을 독점하지 못하게 막는 방어선 역할을 합니다.
숫자별 의미 정리
maxConnections / 5
→ route 제한이 더 작음
→ 독점 방어 강함
→ 병목 가능성 증가
maxConnections / 4
→ 보수적
maxConnections / 3
→ 일반적인 방어형 설정
maxConnections / 2
→ 트래픽 집중 대응 가능
maxConnections
→ route 하나가 전체 풀까지 사용 가능
실무적인 설정 방향
특정 서버의 독점을 막고 싶을 때
- setMaxConnPerRoute(maxConnections / 3)
또는 더 작게 설정할 수 있습니다.
이 방식은:
- 특정 서버 장애 시 전체 풀 보호
- 느린 API의 커넥션 독점 방지
- 전체 시스템 안정성 향상
에 도움이 됩니다.
특정 서버에 요청이 많이 몰릴 때
- setMaxConnPerRoute(maxConnections / 32
또는:
- setMaxConnPerRoute(50) -> 모니터링을 통하여 특정값을 지정
같은 설정을 고려할 수 있습니다.
특정 서버가 실제로 많은 요청을 처리해야 하는 구조라면 route 제한을 너무 낮게 잡으면 오히려 병목이 발생할 수 있습니다.
서버별 트래픽 편차가 클 때
실무에서는 다음 방식이 가장 많이 사용됩니다.
기본 route 제한은 보수적으로 유지 + 특정 route만 예외적으로 증가
예시:
connectionManager.setMaxPerRoute(
new HttpRoute(
new HttpHost("https", "api-heavy.example.com", 443)
),
50
);
Connection Request Timeout 과의 관계
다음 에러가 발생한다면:
- ConnectionRequestTimeoutException
또는:
- Timeout waiting for connection from pool
이는 대부분 커넥션 풀 부족 상황을 의미합니다.
원인은 일반적으로 다음과 같습니다.
maxConnTotal부족maxConnPerRoute부족- 외부 API 응답 지연
- 커넥션 반환 지연
등입니다.
정리
maxConnTotal과 maxConnPerRoute는 역할이 완전히 다릅니다.
- maxConnTotal
= 전체 커넥션 풀의 최대 크기 - maxConnPerRoute
= 특정 서버 하나가 사용할 수 있는 최대 커넥션 수
중요한 점은:
maxConnPerRoute는 보장량이 아닙니다.
각 route가 넘을 수 없는 상한선입니다.
따라서 설정 시에는 단순히 외부 서버 개수로 나누기보다 다음 요소들을 함께 고려해야 합니다.
- 전체 외부 호출량
- 특정 서버로 트래픽이 몰리는 정도
- 외부 서버 장애 가능성
- connection request timeout 발생 여부
- 외부 서버가 감당 가능한 동시 요청 수
- 평균 TPS / Peak TPS
결론
여러 서버를 균등하게 호출하는 구조라면:
- setMaxConnPerRoute(maxConnections / 3)
같은 보수적인 설정이 꽤 안정적입니다.
반대로 특정 서버 하나가 매우 많은 요청을 처리해야 하는 구조라면:
- setMaxConnPerRoute(maxConnections / 2)
또는 고정값 방식이 더 적절할 수 있습니다.
실무에서는 대부분:
- 기본 제한 + 특정 route만 별도 증가
방식을 가장 많이 사용합니다.
※ 기본은 트래픽 모니터링을 통하여 적절한 MaxConnPerRoute값을 도출하는 작업이 선행되어야 합니다.
'프로그래밍 > SpringBoot' 카테고리의 다른 글
| Spring WebFlux의 onError, doOnError, onErrorResume, onStatus 정리 (0) | 2026.05.11 |
|---|---|
| WebClient - java.util.concurrent.TimeoutException (0) | 2026.03.28 |
| WebClient - io.netty.channel.ConnectTimeoutException (0) | 2026.03.28 |
댓글