본문으로 건너뛰기
Advertisement

Apache+Tomcat 연동 실전 고수 팁

Apache+Tomcat 연동 환경에서 발생하는 실제 문제를 진단하고 해결하는 고급 노하우를 다룹니다. mod_jk 상태 페이지 활용, 연결 디버깅, 성능 튜닝, 장애 대응까지 프로덕션 운영에 필요한 기술을 정리합니다.


mod_jk 상태 페이지 활용

mod_jk의 jkstatus 핸들러를 통해 워커 상태와 로드밸런싱 통계를 실시간으로 확인할 수 있습니다.

설정

# workers.properties — 상태 워커 추가
worker.list=worker1,jkstatus

worker.jkstatus.type=status
worker.jkstatus.read_only=true # 운영 환경에서는 읽기 전용 필수
# Apache VirtualHost — 상태 페이지 경로 설정
<Location /jkstatus>
JkMount jkstatus
Require ip 127.0.0.1 10.0.0.0/8 # 내부망만 허용
</Location>

상태 페이지에서 확인할 수 있는 정보

항목설명
StateOK / ERR (워커 상태)
Elected총 처리 요청 수
Errors오류 발생 횟수
Sessions현재 처리 중인 세션 수
Route세션 고정 라우팅 키
LBF로드밸런싱 팩터
# CLI로 상태 확인
curl -s "http://localhost/jkstatus/?mime=prop" | grep worker

# 특정 워커 상태
curl -s "http://localhost/jkstatus/?cmd=show&w=worker1"

# 워커 활성화/비활성화 (read_only=false일 때만)
curl -s "http://localhost/jkstatus/?cmd=update&w=worker1&ac=0" # 비활성화
curl -s "http://localhost/jkstatus/?cmd=update&w=worker1&ac=1" # 활성화

연동 디버깅 — JkLogLevel

JkLogLevel을 높여 상세 로그를 분석합니다.

# mod_jk 로그 레벨 (심각도 순서)
JkLogLevel debug # 가장 상세 (운영 중 사용 금지 — 성능 저하)
JkLogLevel info
JkLogLevel warn # 기본값 권장
JkLogLevel error
# 로그 실시간 모니터링
tail -f /var/log/apache2/mod_jk.log

# 에러 필터링
grep -i "error\|fail\|timeout" /var/log/apache2/mod_jk.log | tail -50

# 특정 워커 관련 로그
grep "worker1" /var/log/apache2/mod_jk.log | tail -30

자주 발생하는 mod_jk 에러

에러 메시지원인해결 방법
Timeout waiting for a replyTomcat 응답 지연socket_timeout 증가, Tomcat 부하 확인
ajp_ilink_receive failedAJP 연결 끊김Tomcat 재시작, 연결 풀 점검
No worker found for nameworkers.properties 설정 오류worker.list 및 워커 이름 확인
All workers are in error state모든 Tomcat 다운Tomcat 프로세스 및 AJP 포트 확인

mod_proxy_http 디버깅

# Apache 에러 로그 레벨 상향 (임시)
LogLevel proxy:debug proxy_http:debug
# mod_proxy 관련 에러만 추출
grep -i "proxy\|ajp\|backend" /var/log/apache2/error.log | tail -50

# 프록시 연결 상태
curl -v http://localhost/ 2>&1 | grep -E "< HTTP|Connected|Request"

# 백엔드(Tomcat) 응답 직접 테스트
curl -v http://127.0.0.1:8080/ 2>&1 | head -30

자주 발생하는 mod_proxy 에러

HTTP 코드에러원인해결 방법
502 Bad Gateway백엔드 응답 없음Tomcat 다운, 포트 불일치Tomcat 상태 확인, ss -tlnp | grep 8080
503 Service Unavailable연결 풀 고갈동시 요청 폭증max 속성 증가, Tomcat 스레드 확인
504 Gateway Timeout응답 시간 초과느린 쿼리/처리timeout 증가, 슬로우 쿼리 분석
500 Internal Server ErrorTomcat 내부 오류애플리케이션 예외Tomcat catalina.out 확인

연결 풀 최적화

mod_jk workers.properties 튜닝

# workers.properties — 연결 풀 최적화
worker.worker1.type=ajp13
worker.worker1.host=127.0.0.1
worker.worker1.port=8009

# 연결 풀 크기 = Tomcat maxThreads의 75~80%
worker.worker1.connection_pool_size=75

# 유휴 연결 타임아웃: 장시간 미사용 연결 정리
worker.worker1.connection_pool_timeout=600

# 소켓 타임아웃: Tomcat 응답 최대 대기 시간
worker.worker1.socket_timeout=60

# TCP keepalive: 방화벽이 연결을 끊는 경우 활성화
worker.worker1.socket_keepalive=true

# 재시도 설정
worker.worker1.retries=2
worker.worker1.recovery_options=7

mod_proxy_http 연결 풀 튜닝

# 글로벌 프록시 연결 설정
<IfModule mod_proxy.c>
# 총 열린 연결 수 제한
ProxyMaxForwards 10
</IfModule>

# ProxyPass 속성으로 세밀한 제어
ProxyPass / http://127.0.0.1:8080/ \
connectiontimeout=5 \ # 연결 수립 최대 5초
timeout=60 \ # 응답 최대 60초
retry=0 \ # 오류 시 즉시 재시도 (0=즉시)
acquire=3000 \ # 연결 풀 대기 최대 3초
max=100 \ # 최대 100개 연결
ttl=300 # 연결 최대 재사용 300초

# keepalive 활성화 (Tomcat과 TCP 연결 유지)
SetEnv proxy-nokeepalive 0
SetEnv proxy-initial-not-pooled 0

헤더 디버깅

클라이언트 IP, SSL 정보가 Tomcat에 올바르게 전달되는지 확인합니다.

# 디버깅용 응답 헤더에 내부 정보 노출 (개발 환경만)
<VirtualHost *:443>
Header always set X-Debug-Remote-Addr "%{REMOTE_ADDR}s"
Header always set X-Debug-Forwarded-For "%{X-Forwarded-For}e"
Header always set X-Debug-Proto "%{X-Forwarded-Proto}e"
</VirtualHost>
# Tomcat에서 수신한 헤더 확인 (Spring Boot)
# application.properties
# logging.level.org.apache.tomcat=DEBUG

# curl로 헤더 확인
curl -I -H "X-Test: hello" https://example.com/

세션 고정(Sticky Session) 트러블슈팅

# Tomcat 1에서 생성된 세션 확인
curl -c cookies.txt https://example.com/login
cat cookies.txt
# JSESSIONID=abc123.tomcat1 ← .tomcat1 부분이 라우팅 키

# 다음 요청에서 같은 Tomcat으로 라우팅 확인
curl -b cookies.txt https://example.com/dashboard

세션 고정 실패 시 점검 목록

1. Tomcat server.xml — jvmRoute 설정 확인
<Engine jvmRoute="tomcat1">

2. workers.properties — route 설정 확인
worker.tomcat1.route=tomcat1

3. JSESSIONID 쿠키에 .tomcat1 suffix 포함 여부 확인

4. sticky_session=true 설정 확인
worker.lb_worker.sticky_session=true

5. 세션 만료 또는 Tomcat 재시작으로 인한 세션 분실
→ sticky_session_force=false (다른 노드로 폴백 허용)

Apache 설정 검증 자동화

# 설정 문법 검사
sudo apache2ctl configtest

# 모듈 로드 확인
apache2ctl -M | grep -E "proxy|jk|headers|rewrite|ssl"

# VirtualHost 목록 확인
apache2ctl -S

# 실제 요청 처리 경로 추적 (Apache 2.4)
# mod_remoteip 트레이스

프록시 요청 로깅

# 프록시 요청/응답 로그 포맷
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D" combined_timing

# 처리 시간(%D)이 3000ms(3초) 초과인 느린 요청 로깅
SetEnvIf Request_URI ".*" slow_request=0
# (커스텀 로그 분석 스크립트 사용)

CustomLog ${APACHE_LOG_DIR}/access.log combined_timing
# 느린 요청 상위 10개 (처리 시간 기준)
awk '{print $NF, $0}' /var/log/apache2/access.log | sort -rn | head -10

# 5xx 에러 요청만 추출
grep ' 5[0-9][0-9] ' /var/log/apache2/access.log | tail -50

# 시간당 요청 수
awk '{print $4}' /var/log/apache2/access.log | \
cut -d: -f2 | sort | uniq -c | sort -rn

점검 모드 (Graceful Maintenance)

# 점검 페이지 설정
<VirtualHost *:443>
ServerName example.com

# 점검 플래그 파일이 존재하면 503 반환
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}/maintenance.flag -f
RewriteCond %{REQUEST_URI} !=/maintenance.html
RewriteRule ^ /maintenance.html [R=503,L]

ErrorDocument 503 /maintenance.html
Alias /maintenance.html /var/www/maintenance.html
</VirtualHost>
# 점검 시작
touch /var/www/html/maintenance.flag

# 점검 종료
rm /var/www/html/maintenance.flag

보안 강화 체크리스트

# 서버 정보 숨기기
ServerTokens Prod # "Apache" 만 노출 (버전 숨김)
ServerSignature Off # 에러 페이지 서버 정보 제거

# 불필요한 HTTP 메서드 차단
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>

# 디렉터리 탐색 차단
<Directory />
Options -Indexes
AllowOverride None
</Directory>

# Slowloris 방어
RequestReadTimeout header=20,MinRate=500 body=20,MinRate=500

한 눈에 보는 진단 명령어

# 1. 포트 상태 확인
ss -tlnp | grep -E "80|443|8080|8009"

# 2. Apache 설정 검증
sudo apache2ctl configtest && echo "OK"

# 3. 모듈 확인
apache2ctl -M | grep -E "proxy_http|proxy_ajp|jk"

# 4. Tomcat 연결 테스트
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/

# 5. Apache → Tomcat 프록시 경로 테스트
curl -s -o /dev/null -w "%{http_code}" http://localhost/

# 6. SSL 인증서 만료 확인
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates

# 7. 에러 로그 실시간 모니터링
sudo tail -f /var/log/apache2/error.log

Summary

항목도구/방법
mod_jk 상태 모니터링/jkstatus 핸들러 + worker.jkstatus.type=status
연동 디버깅JkLogLevel debug / LogLevel proxy:debug
연결 풀 튜닝connection_pool_size / max=100 ttl=300
세션 고정 확인JSESSIONID .tomcat1 suffix + jvmRoute
설정 검증apache2ctl configtest + apache2ctl -M
느린 요청 분석%D 로그 포맷 + awk 스크립트
점검 모드maintenance.flag 파일 + RewriteCond
보안 강화ServerTokens Prod + RequestReadTimeout
Advertisement