Tomcat 10 운영자 튜닝 가이드(커넥터·스레드풀·압축·헤더 최적화)
Tomcat 10은 “설치하면 바로 돌아가는” 웹 애플리케이션 서버이지만,
실제 운영 환경에서는 트래픽 패턴, 업로드 규모, 프록시 구조에 따라 병목이 매우 쉽게 발생합니다.
이 글은 Tomcat 10 + JDK 21 조합을 기준으로, 설치 이후 반드시 점검해야 하는 커넥터 튜닝, 스레드풀, 압축, 업로드 제한, 보안 헤더까지 실전 중심으로 정리한 운영 가이드입니다.
Tomcat을 단독으로 쓰는 경우는 거의 없기 때문에, Nginx Reverse Proxy와의 연동까지 함께 다룹니다.

1) Tomcat 10 설치 (tar.gz 권장)
Tomcat을 설치하는 방법은 크게 두 가지입니다.
① tar.gz 수동 설치는 최신 버전 유지와 업그레이드가 쉽고,
② apt 패키지 설치는 빠르지만 버전 고정이라는 단점이 있습니다.
운영 환경에서는 보안 패치나 10.1.x 라인 업데이트가 필요하므로 tar.gz 설치를 권장합니다.
1-1) tar.gz 수동 설치
cd /opt
sudo curl -LO https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.25/bin/apache-tomcat-10.1.25.tar.gz
sudo tar xzf apache-tomcat-10.1.25.tar.gz
sudo mv apache-tomcat-10.1.25 tomcat
sudo useradd -r -s /usr/sbin/nologin tomcat
sudo chown -R tomcat:tomcat /opt/tomcat
1-2) apt 패키지 설치
sudo apt update && sudo apt install -y tomcat10 tomcat10-admin
systemctl status tomcat10
2) systemd 서비스 등록
수동 설치 시에는 systemd로 서비스 등록을 해야 운영 편의성이 올라갑니다.
JDK 경로, CATALINA_BASE, 재시작 정책 등을 운영 환경에 맞게 수정하세요.
sudo tee /etc/systemd/system/tomcat.service > /dev/null <<'EOF'
[Unit]
Description=Apache Tomcat 10
After=network.target
[Service]
Type=forking
User=tomcat
Group=tomcat
Environment="JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_OPTS=-Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now tomcat
3) JVM 옵션(setenv.sh)
Tomcat 성능의 절반은 JVM 설정이 결정합니다.
Heap 용량, GC 알고리즘, 파일 인코딩, urandom 설정 등을 반드시 점검하세요.
sudo tee /opt/tomcat/bin/setenv.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
export JAVA_OPTS="${JAVA_OPTS} -Xms512m -Xmx1024m -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
export JAVA_OPTS="${JAVA_OPTS} -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom"
EOF
sudo chmod +x /opt/tomcat/bin/setenv.sh

4) 커넥터 튜닝(server.xml)
Tomcat의 핵심 병목은 대부분 Connector에서 발생합니다.
maxThreads, acceptCount, keepAliveTimeout, 압축 설정을 반드시 조정해야 합니다.
대부분 Nginx 리버스 프록시 뒤에 두는 구성으로 운영하므로 그 기준으로 설정합니다.
- maxThreads: CPU 코어 × 50~100 권장
- acceptCount: 스레드 포화 시 대기열
- compression: Nginx에서 gzip 사용 중이면 Tomcat 압축 off 가능
- server="-"로 Tomcat 버전 노출 방지
5) 업로드/POST 사이즈 설정
Spring Boot를 쓴다면 application.yml에서도 설정 가능합니다.
spring:
servlet:
multipart:
max-file-size: 50MB
max-request-size: 60MB
6) 접근 로그·보안 헤더 설정
보안 헤더(HSTS, CSP, XSS 보호)는 Nginx에서 통합 관리하는 것을 권장합니다.

7) Nginx Reverse Proxy 연동
Tomcat을 외부에 직접 노출하지 않고, 모든 요청은 Nginx를 통해 들어오도록 구성합니다.
특히 keepalive, X-Forwarded-* 헤더, gzip 압축 정책을 반드시 체크해야 합니다.
upstream app_upstream {
server 127.0.0.1:8080;
keepalive 64;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://app_upstream;
}
}
8) AJP는 비권장(보안 이슈)
AJP Ghost 취약점 이후, AJP는 내부망에서만 제한적으로 사용하는 것을 권장합니다.
대부분의 운영 환경에서는 Nginx + HTTP 구성이 훨씬 단순하고 안전합니다.
9) JDK·암호화 스위트 권장 조합
- JDK 21 + Tomcat 10.1.x 조합 권장
- HTTPS는 프론트(Nginx)에서 처리하고 Tomcat 내부는 HTTP 유지
- 암호화 스위트는 운영 정책에 따라 Nginx 레이어에서 통일
10) 최종 점검 체크리스트
- 스레드풀 포화 여부(maxThreads, busyThreads)
- 큐 대기열(acceptCount) 증가 여부
- GC 지연·Heap 누수 여부
- 압축 중복 여부(nginx vs tomcat)
- 접근 로그·에러 로그 분리 및 로테이션 구성
실전 장애 사례로 보는 튜닝 기준
운영에서 자주 만나는 톰캣 병목은 거의 패턴이 정해져 있습니다.
① maxThreads 포화: busyThreads가 maxThreads에 붙어있는 시간이 길어짐 → 응답 지연/타임아웃 증가
② acceptCount 대기열 폭증: 큐에 쌓이면서 p95 지연이 급격히 튀는 구간 발생
③ keepAliveTimeout 과다: 연결이 오래 붙어 CPU가 아닌 “연결 수”가 한계가 됨
즉, 튜닝은 값 자체보다
busyThreads / currentThreadsBusy / requestCount / errorCount 같은 “지표 기반”으로 해야 안전합니다.
부하 테스트(Locust/JMeter)로 지표를 찍어보면서 조정하는 것을 최종 권장합니다.
👉 1편: Ubuntu 24.04에서 Nginx로 무료 SSL(HTTPS) 적용
👉 5편: Gradle 빌드 최적화로 빌드 50% 줄이기
👉 6편: Spring Security 6 JWT 로그인/리프레시 토큰
👉 7편: JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략
👉 8편: Docker로 PostgreSQL 운영(백업/복구/업그레이드)
'서버 인프라 실무' 카테고리의 다른 글
| JPA N+1 완전 정복: 자동 감지부터 fetch join·EntityGraph·batch_size 실전 해결 전략 (0) | 2025.10.09 |
|---|---|
| Gradle 빌드 캐시/병렬/Configuration Cache로 빌드 50% 줄이기 (0) | 2025.10.08 |
| systemd 서비스로 스프링부트 배포: 로그 분리·자동 재시작까지 (0) | 2025.10.07 |
| UFW 방화벽 실전 규칙: SSH 잠그고, 웹만 열고, 포트스캔 막기 (0) | 2025.10.06 |
| Ubuntu 24.04에서 Nginx로 무료 SSL(HTTPS) 적용(이중 인증서 자동갱신) (0) | 2025.10.06 |