Tomcat HTTP 커넥터 설정
Tomcat의 HTTP 커넥터는 클라이언트 요청을 수신하는 네트워크 입구입니다. maxThreads, acceptCount, connectionTimeout 등의 파라미터를 올바르게 튜닝하면 처리량과 응답성을 크게 개선할 수 있습니다.
HTTP 커넥터 기본 구조
<!-- server.xml -->
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"/>
protocol 속성 값에 따라 커넥터 구현체가 결정됩니다.
| protocol 값 | 구현체 | 특징 |
|---|---|---|
HTTP/1.1 | NIO (자동 선택) | 기본값, 논블로킹 I/O |
org.apache.coyote.http11.Http11NioProtocol | NIO | 명시적 NIO |
org.apache.coyote.http11.Http11Nio2Protocol | NIO2 | 비동기 I/O |
org.apache.coyote.http11.Http11AprProtocol | APR/Native | 네이티브 라이브러리 필요 |
핵심 파라미터
스레드 풀 설정
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="75"
acceptCount="100"
connectionTimeout="20000"/>
| 파라미터 | 설명 | 기본값 | 권장값 |
|---|---|---|---|
maxThreads | 최대 동시 처리 스레드 수 | 200 | CPU 코어 × 50~100 |
minSpareThreads | 항상 유지할 최소 대기 스레드 | 10 | 10~25 |
maxSpareThreads | 최대 유휴 스레드 수 | 75 | maxThreads × 0.3 |
acceptCount | 모든 스레드가 바쁠 때 대기 큐 크기 | 100 | maxThreads × 0.5 |
동작 흐름:
요청 도착
↓
[사용 가능한 스레드 있음?]
↓ Yes → 즉시 처리
↓ No → acceptCount 큐에 대기
↓ 큐도 꽉 참 → Connection Refused
타임아웃 설정
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
keepAliveTimeout="15000"
maxKeepAliveRequests="100"/>
| 파라미터 | 설명 | 기본값 |
|---|---|---|
connectionTimeout | 첫 요청 라인 수신 대기 시간(ms) | 20000 (20초) |
keepAliveTimeout | Keep-Alive 유지 시간(ms) | connectionTimeout 값 |
maxKeepAliveRequests | Keep-Alive 연결당 최대 요청 수 | 100 |
프로덕션 팁: Nginx/Apache가 앞단에 있다면
keepAliveTimeout을 충분히 길게 설정합니다 (프록시 keepalive 시간과 동기화).
연결 및 요청 크기 제한
<Connector port="8080" protocol="HTTP/1.1"
maxConnections="10000"
maxHttpHeaderSize="8192"
maxPostSize="2097152"
maxParameterCount="1000"/>
| 파라미터 | 설명 | 기본값 |
|---|---|---|
maxConnections | NIO: 최대 동시 연결 수 | 10000 |
maxHttpHeaderSize | 요청/응답 헤더 최대 크기(bytes) | 8192 (8KB) |
maxPostSize | POST 본문 최대 크기(bytes) | 2097152 (2MB) |
maxParameterCount | 최대 파라미터 수 | 10000 (Tomcat 10.1) |
HTTPS 커넥터 설정
방법 1: Java Keystore(JKS) 사용
# 자체 서명 인증서 생성 (테스트용)
keytool -genkey -alias tomcat \
-keyalg RSA -keysize 2048 \
-keystore /opt/tomcat/conf/keystore.jks \
-validity 365 \
-storepass changeit \
-keypass changeit \
-dname "CN=localhost, OU=Dev, O=MyCompany, L=Seoul, ST=Seoul, C=KR"
<!-- HTTPS 커넥터 (JKS) -->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/keystore.jks"
certificateKeystorePassword="changeit"
type="RSA"/>
</SSLHostConfig>
</Connector>
방법 2: PEM 인증서 직접 사용 (Let's Encrypt 등)
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150"
SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateFile="/etc/letsencrypt/live/example.com/cert.pem"
certificateKeyFile="/etc/letsencrypt/live/example.com/privkey.pem"
certificateChainFile="/etc/letsencrypt/live/example.com/chain.pem"
type="RSA"/>
</SSLHostConfig>
</Connector>
프로덕션 권장: Tomcat에서 직접 SSL을 처리하기보다 Nginx/Apache에서 SSL Termination 후 HTTP로 Tomcat에 전달하는 패턴을 사용합니다. 성능과 인증서 관리가 훨씬 편리합니다.
압축(Gzip) 설정
<Connector port="8080" protocol="HTTP/1.1"
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/plain,text/css,
application/json,application/javascript"/>
| 파라미터 | 설명 | 기본값 |
|---|---|---|
compression | on/off/force | off |
compressionMinSize | 압축 적용 최소 응답 크기(bytes) | 2048 |
compressibleMimeType | 압축 대상 MIME 타입 | — |
스레드 풀 공유 (Executor)
여러 커넥터가 하나의 스레드 풀을 공유할 때 Executor를 사용합니다.
<!-- 공유 스레드 풀 정의 -->
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="400"
minSpareThreads="20"
maxQueueSize="100"
prestartminSpareThreads="true"/>
<!-- 커넥터에서 Executor 참조 -->
<Connector port="8080" protocol="HTTP/1.1"
executor="tomcatThreadPool"
connectionTimeout="20000"/>
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
executor="tomcatThreadPool"
SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateFile="conf/cert.pem"
certificateKeyFile="conf/key.pem"/>
</SSLHostConfig>
</Connector>
X-Forwarded-For 설정 (리버스 프록시 환경)
Nginx나 Apache 앞에서 프록시될 때 실제 클라이언트 IP를 Tomcat에 전달합니다.
<!-- RemoteIpValve: X-Forwarded-For 헤더를 실제 IP로 처리 -->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
proxiesHeader="x-forwarded-by"
protocolHeader="x-forwarded-proto"
internalProxies="127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+"/>
이 Valve를 설정하면 request.getRemoteAddr()가 실제 클라이언트 IP를 반환하고, request.isSecure()가 HTTPS 여부를 올바르게 반환합니다.
커넥터 성능 튜닝 — 실전 체크리스트
소규모 서버 (2 CPU, 4GB RAM)
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="100"
minSpareThreads="10"
acceptCount="50"
connectionTimeout="10000"
keepAliveTimeout="10000"
maxKeepAliveRequests="50"/>
중규모 서버 (48 CPU, 816GB RAM)
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="300"
minSpareThreads="25"
acceptCount="150"
connectionTimeout="20000"
keepAliveTimeout="15000"
maxKeepAliveRequests="100"
maxConnections="10000"/>
대규모 서버 (16+ CPU, 32GB+ RAM)
<Executor name="tomcatThreadPool"
maxThreads="800"
minSpareThreads="50"
maxQueueSize="200"/>
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
executor="tomcatThreadPool"
connectionTimeout="30000"
maxConnections="20000"/>
커넥터 상태 모니터링
JMX를 통해 커넥터 상태를 실시간으로 확인할 수 있습니다.
# setenv.sh에 JMX 활성화 추가
export CATALINA_OPTS="$CATALINA_OPTS \
-Dcom.sun.management.jmxremote \
-Dcom.sun.management.jmxremote.port=9090 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false"
또는 tomcat-manager 웹 앱을 통해 현재 활성 스레드 수, 처리된 요청 수 등을 확인할 수 있습니다.
Summary
| 설정 | 파라미터 | 권장 기준 |
|---|---|---|
| 최대 스레드 | maxThreads | CPU 코어 수 × 50 (IO 바운드) |
| 대기 큐 | acceptCount | maxThreads × 0.5 |
| 연결 타임아웃 | connectionTimeout | 10000~20000ms |
| 스레드 공유 | Executor | 커넥터 2개 이상일 때 사용 |
| 실제 IP 전달 | RemoteIpValve | 리버스 프록시 필수 |
| 압축 | compression="on" | JSON/HTML 응답에 권장 |