Tomcat Configuration
server.xml, Connector 튜닝, JVM 옵션, 다중 인스턴스
📚 시리즈 네비게이션
| 이전 | 현재 | 다음 |
|---|---|---|
| Nginx + Tomcat | Tomcat Configuration | - |
→ 시리즈 목차
🏗️ server.xml 구조
전체 계층
<Server> <!-- Tomcat 인스턴스 -->
<Listener /> <!-- 이벤트 리스너 -->
<GlobalNamingResources /> <!-- 전역 JNDI 리소스 -->
<Service> <!-- 서비스 (Connector + Engine) -->
<Connector /> <!-- 클라이언트 연결 (HTTP, AJP) -->
<Connector />
<Engine> <!-- 요청 처리 엔진 -->
<Realm /> <!-- 인증/권한 -->
<Host> <!-- 가상 호스트 -->
<Valve /> <!-- 요청/응답 처리 -->
<Context /> <!-- 웹 애플리케이션 -->
</Host>
</Engine>
</Service>
</Server>
요청 처리 흐름
🔌 Connector 상세 설정
HTTP Connector
<Connector port="8080"
protocol="HTTP/1.1"
<!-- 연결 관련 -->
connectionTimeout="20000"
maxConnections="8192"
acceptCount="100"
<!-- 스레드 풀 -->
maxThreads="200"
minSpareThreads="10"
<!-- 요청 처리 -->
maxPostSize="2097152"
URIEncoding="UTF-8"
<!-- Keep-Alive -->
keepAliveTimeout="20000"
maxKeepAliveRequests="100"
<!-- 압축 -->
compression="on"
compressionMinSize="2048"
compressibleMimeType="text/html,text/xml,text/plain,text/css,
text/javascript,application/javascript,
application/json,application/xml"
redirectPort="8443" />
주요 속성
연결 관련
| 속성 | 기본값 | 설명 |
|---|---|---|
port | 8080 | 리스닝 포트 |
connectionTimeout | 20000 | 연결 타임아웃 (ms) |
maxConnections | 8192 (NIO) | 최대 동시 연결 수 |
acceptCount | 100 | 대기 큐 크기 |
스레드 풀
| 속성 | 기본값 | 설명 |
|---|---|---|
maxThreads | 200 | 최대 처리 스레드 |
minSpareThreads | 10 | 최소 유휴 스레드 |
maxQueueSize | Integer.MAX | 대기 작업 큐 크기 |
요청 처리
| 속성 | 기본값 | 설명 |
|---|---|---|
maxPostSize | 2097152 (2MB) | 최대 POST 크기 |
maxParameterCount | 10000 | 최대 파라미터 수 |
URIEncoding | ISO-8859-1 | URI 인코딩 |
Connector Protocol
<!-- BIO (Blocking I/O) - Tomcat 8.5+에서 제거됨 -->
<Connector protocol="HTTP/1.1" />
<!-- NIO (Non-blocking I/O) - 기본값 -->
<Connector protocol="org.apache.coyote.http11.Http11NioProtocol" />
<!-- NIO2 -->
<Connector protocol="org.apache.coyote.http11.Http11Nio2Protocol" />
<!-- APR (Apache Portable Runtime) - 네이티브 라이브러리 필요 -->
<Connector protocol="org.apache.coyote.http11.Http11AprProtocol" />
| Protocol | 특징 | 권장 |
|---|---|---|
| NIO | Java NIO 기반, 적은 스레드로 많은 연결 | ◎ |
| NIO2 | Java NIO2 기반, NIO보다 약간 나음 | ○ |
| APR | 네이티브 라이브러리, SSL 성능 좋음 | △ |
Executor (공유 스레드 풀)
여러 Connector가 스레드 풀을 공유함:
<Service name="Catalina">
<!-- 공유 스레드 풀 정의 -->
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="300"
minSpareThreads="20"
maxQueueSize="100" />
<!-- Connector에서 Executor 사용 -->
<Connector port="8080"
protocol="HTTP/1.1"
executor="tomcatThreadPool"
connectionTimeout="20000" />
<Connector port="8009"
protocol="AJP/1.3"
executor="tomcatThreadPool" />
</Service>
🌐 Host 설정
기본 Host
<Host name="localhost"
appBase="webapps"
unpackWARs="true"
autoDeploy="true">
<!-- 접근 로그 -->
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b %D" />
</Host>
| 속성 | 설명 |
|---|---|
name | 호스트명 (도메인) |
appBase | 애플리케이션 디렉토리 |
unpackWARs | WAR 자동 압축 해제 |
autoDeploy | 자동 배포 (개발용, 운영에서는 false) |
가상 호스트 추가
<Engine name="Catalina" defaultHost="localhost">
<!-- 기본 호스트 -->
<Host name="localhost" appBase="webapps">
...
</Host>
<!-- 추가 가상 호스트 -->
<Host name="example.com" appBase="/var/www/example">
<Alias>www.example.com</Alias>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="example_access_log"
suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="api.example.com" appBase="/var/www/api">
...
</Host>
</Engine>
📦 Context 설정
Context 정의 위치
| 위치 | 우선순위 | 용도 |
|---|---|---|
$CATALINA_HOME/conf/server.xml | 1 | 서버 레벨 (권장 안 함) |
$CATALINA_HOME/conf/Catalina/localhost/*.xml | 2 | 호스트별 설정 |
webapps/myapp/META-INF/context.xml | 3 | 앱 내장 |
$CATALINA_HOME/conf/context.xml | 4 | 전역 기본값 |
Context 설정 예시
<!-- $CATALINA_HOME/conf/Catalina/localhost/myapp.xml -->
<Context docBase="/opt/apps/myapp" path="/myapp" reloadable="false">
<!-- DataSource -->
<Resource name="jdbc/mydb"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb?useSSL=false"
username="appuser"
password="password"
maxTotal="50"
maxIdle="20"
minIdle="5"
maxWaitMillis="10000"
validationQuery="SELECT 1"
testOnBorrow="true" />
<!-- 환경 변수 -->
<Environment name="appEnv" type="java.lang.String" value="production" />
</Context>
ROOT 애플리케이션 설정
<!-- $CATALINA_HOME/conf/Catalina/localhost/ROOT.xml -->
<Context docBase="/opt/apps/myapp" path="">
...
</Context>
☕ JVM 옵션 설정
setenv.sh 생성
#!/bin/bash
# $CATALINA_HOME/bin/setenv.sh
# 힙 메모리
CATALINA_OPTS="$CATALINA_OPTS -Xms1g"
CATALINA_OPTS="$CATALINA_OPTS -Xmx2g"
# Metaspace (Java 8+)
CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=256m"
CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=512m"
# GC 설정 (G1GC 권장)
CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
CATALINA_OPTS="$CATALINA_OPTS -XX:MaxGCPauseMillis=200"
CATALINA_OPTS="$CATALINA_OPTS -XX:+ParallelRefProcEnabled"
# GC 로그 (Java 11+)
CATALINA_OPTS="$CATALINA_OPTS -Xlog:gc*:file=$CATALINA_HOME/logs/gc.log:time,uptime:filecount=5,filesize=10M"
# 인코딩
CATALINA_OPTS="$CATALINA_OPTS -Dfile.encoding=UTF-8"
CATALINA_OPTS="$CATALINA_OPTS -Dsun.jnu.encoding=UTF-8"
# 타임존
CATALINA_OPTS="$CATALINA_OPTS -Duser.timezone=Asia/Seoul"
# HeapDump (OOM 발생 시)
CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
CATALINA_OPTS="$CATALINA_OPTS -XX:HeapDumpPath=$CATALINA_HOME/logs/"
# JMX 원격 모니터링 (선택)
#CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
#CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=9090"
#CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
#CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
export CATALINA_OPTS
JVM 메모리 가이드
| 용도 | Xms | Xmx | 참고 |
|---|---|---|---|
| 개발 | 256m | 512m | 가볍게 |
| 소규모 | 512m | 1g | 트래픽 적음 |
| 중규모 | 1g | 2g | 일반적 |
| 대규모 | 2g | 4g+ | 트래픽 많음 |
팁: Xms와 Xmx를 같게 설정하면 힙 리사이징 오버헤드 감소.
GC 선택 가이드
| GC | 특징 | 권장 환경 |
|---|---|---|
| G1GC | 균형잡힌 성능, 예측 가능한 지연 | 대부분의 경우 (기본) |
| ZGC | 초저지연 (<1ms), Java 11+ | 저지연 필수 |
| Shenandoah | 저지연, Red Hat | 저지연 필요 |
| ParallelGC | 높은 처리량, 긴 GC 시간 | 배치 작업 |
# G1GC (권장)
-XX:+UseG1GC
# ZGC (Java 15+에서 프로덕션 준비)
-XX:+UseZGC
# Shenandoah (Java 12+)
-XX:+UseShenandoahGC
📊 Valve (밸브) 설정
Access Log Valve
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="access"
suffix=".log"
rotatable="true"
fileDateFormat="yyyy-MM-dd"
pattern="%h %l %u %t "%r" %s %b %D %{X-Forwarded-For}i" />
패턴 문자:
| 패턴 | 설명 |
|---|---|
%h | 원격 호스트 (IP) |
%l | 원격 로그인 이름 (보통 -) |
%u | 인증된 사용자 |
%t | 시간 |
%r | 요청 첫 줄 (메서드, URI, 프로토콜) |
%s | HTTP 상태 코드 |
%b | 응답 바이트 |
%D | 처리 시간 (밀리초) |
%T | 처리 시간 (초) |
%{header}i | 요청 헤더 |
Remote IP Valve
프록시 뒤에서 실제 클라이언트 IP 인식:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto"
internalProxies="192\.168\.1\.\d+|127\.0\.0\.1" />
Error Report Valve
에러 페이지 커스터마이징:
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false"
showServerInfo="false" />
Stuck Thread Detection Valve
멈춘 스레드 감지:
<Valve className="org.apache.catalina.valves.StuckThreadDetectionValve"
threshold="600"
interruptThreadThreshold="0" />
🔐 보안 설정
불필요한 앱 제거
# 기본 앱 제거 (운영 환경)
rm -rf $CATALINA_HOME/webapps/docs
rm -rf $CATALINA_HOME/webapps/examples
rm -rf $CATALINA_HOME/webapps/host-manager
# rm -rf $CATALINA_HOME/webapps/manager # 필요하면 유지
rm -rf $CATALINA_HOME/webapps/ROOT # 기본 페이지
Manager 앱 접근 제한
<!-- $CATALINA_HOME/webapps/manager/META-INF/context.xml -->
<Context antiResourceLocking="false" privileged="true">
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1|192\.168\.1\.\d+" />
</Context>
서버 정보 숨기기
<!-- server.xml의 Connector -->
<Connector port="8080"
server="Server"
... />
<!-- Host 내부에 ErrorReportValve -->
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false"
showServerInfo="false" />
AJP 보안 (Tomcat 9.0.31+)
<Connector port="8009"
protocol="AJP/1.3"
address="127.0.0.1"
secretRequired="true"
secret="your-secret-key" />
Shutdown 포트 보안
<!-- 복잡한 문자열 사용 또는 비활성화 -->
<Server port="8005" shutdown="COMPLEX_SHUTDOWN_STRING">
<!-- 또는 완전 비활성화 -->
<Server port="-1" shutdown="SHUTDOWN">
🗂️ 다중 인스턴스 구성
CATALINA_HOME vs CATALINA_BASE
| 변수 | 설명 | 공유 |
|---|---|---|
CATALINA_HOME | Tomcat 설치 디렉토리 (바이너리) | 공유 가능 |
CATALINA_BASE | 인스턴스별 설정/데이터 | 인스턴스별 분리 |
디렉토리 구조
/opt/tomcat/ # CATALINA_HOME (공유)
├── bin/
├── lib/
└── ...
/var/tomcat/instance1/ # CATALINA_BASE (인스턴스 1)
├── conf/
│ ├── server.xml # 포트: 8080, 8005, 8009
│ └── ...
├── logs/
├── temp/
├── webapps/
└── work/
/var/tomcat/instance2/ # CATALINA_BASE (인스턴스 2)
├── conf/
│ ├── server.xml # 포트: 8081, 8006, 8010
│ └── ...
├── logs/
├── temp/
├── webapps/
└── work/
인스턴스 생성 스크립트
#!/bin/bash
# create-instance.sh
CATALINA_HOME=/opt/tomcat
INSTANCE_NAME=$1
INSTANCE_BASE=/var/tomcat/$INSTANCE_NAME
# 디렉토리 생성
mkdir -p $INSTANCE_BASE/{conf,logs,temp,webapps,work}
# 설정 파일 복사
cp -r $CATALINA_HOME/conf/* $INSTANCE_BASE/conf/
# 권한 설정
chown -R tomcat:tomcat $INSTANCE_BASE
echo "Instance created at $INSTANCE_BASE"
echo "Edit $INSTANCE_BASE/conf/server.xml to change ports"
인스턴스 실행
#!/bin/bash
# instance1-start.sh
export CATALINA_HOME=/opt/tomcat
export CATALINA_BASE=/var/tomcat/instance1
$CATALINA_HOME/bin/startup.sh
#!/bin/bash
# instance1-stop.sh
export CATALINA_HOME=/opt/tomcat
export CATALINA_BASE=/var/tomcat/instance1
$CATALINA_HOME/bin/shutdown.sh
Systemd 서비스 (다중 인스턴스)
# /etc/systemd/system/tomcat@.service
[Unit]
Description=Apache Tomcat %i
After=network.target
[Service]
Type=forking
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_BASE=/var/tomcat/%i"
Environment="CATALINA_PID=/var/tomcat/%i/tomcat.pid"
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
User=tomcat
Group=tomcat
[Install]
WantedBy=multi-user.target
# 사용법
systemctl start tomcat@instance1
systemctl start tomcat@instance2
systemctl enable tomcat@instance1
📋 튜닝 체크리스트
성능
| 항목 | 확인 |
|---|---|
| Connector maxThreads 조정 | ☐ |
| Connector maxConnections 조정 | ☐ |
| JVM 힙 메모리 설정 | ☐ |
| GC 알고리즘 선택 (G1GC) | ☐ |
| Keep-Alive 설정 | ☐ |
| 압축 (compression) 설정 | ☐ |
보안
| 항목 | 확인 |
|---|---|
| 불필요한 기본 앱 제거 | ☐ |
| Manager 앱 접근 제한 | ☐ |
| 서버 정보 숨기기 | ☐ |
| Shutdown 포트 보안 | ☐ |
| AJP 보안 설정 (필요시) | ☐ |
운영
| 항목 | 확인 |
|---|---|
| Access 로그 설정 | ☐ |
| GC 로그 설정 | ☐ |
| HeapDump 설정 | ☐ |
| 로그 로테이션 | ☐ |
| autoDeploy=false (운영) | ☐ |
🔗 시리즈 네비게이션
| 이전 | 다음 |
|---|---|
| Nginx + Tomcat Integration | - |