Tomcat 성능 테스트의 핵심 지표와 실질적 최적화 전략
Apache Tomcat은 자바 웹 애플리케이션을 배포하는 대표적인 오픈소스 서블릿 컨테이너로, 시스템의 응답성과 안정성에 직접적인 영향을 미칩니다. 본 문서는 실제 운영 환경에서 유의미한 성능 개선을 가능하게 하는 10가지 주요 지표를 중심으로 분석하고, 각 지표에 따른 구체적인 조정 방안을 제시합니다.
-
초당 요청 처리량 (RPS) 서버의 동시 처리 능력을 판단하는 가장 기본적인 지표입니다.
maxThreads설정(기본값 150)을 기준으로 부하 테스트 도구(예: JMeter)를 활용해 다양한 동시 접속 수에서의 처리량 변화를 측정합니다. 처리량 증가가 정체되면 리소스 한계(스레드, 메모리 등)를 의심해야 합니다. -
평균 응답 시간 (Latency) 클라이언트 요청부터 응답 완료까지 걸리는 시간이며, 사용자 경험에 직결됩니다.
connectionTimeout매개변수(기본 20초)는 연결 대기 시간을 제어하며, 너무 짧으면 연결 끊김이 발생하고, 너무 길면 리소스 낭비가 됩니다. 로그 파일(catalina.out) 내에서 특정 요청의 처리 시간을 추적하여 지연 원인을 분석할 수 있습니다. -
오류 발생 비율 HTTP 상태 코드 중 4xx(클라이언트 오류), 5xx(서버 오류)의 비율을 모니터링하면 시스템 안정성을 파악할 수 있습니다. 로깅 설정을 통해 세부 정보를 수집하기 위해
logging.properties파일에 다음 설정을 추가합니다:
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = FINE
- 스레드 풀 사용률
Tomcat의 요청 처리는 내부 스레드 풀을 기반으로 이루어집니다.
maxThreads,minSpareThreads,acceptCount파라미터는 동시 처리 가능 수와 대기 큐 크기를 결정합니다.acceptCount를 초과하는 요청은 대기열에서 대기하며, 이 값이 자주 도달한다면 스레드 수 증가나 프록시 도입을 고려해야 합니다. JMX를 통해Catalina:type=ThreadPool,name="http-nio-8080"객체의 속성을 실시간 확인할 수 있습니다.
도식: NIO 기반 요청 처리 과정에서 Acceptor, Poller, Worker 스레드 간의 협업 구조
- 연결기 구성 최적화 HTTP 요청을 수신하는 연결기의 성능은 전체 성능에 큰 영향을 미칩니다. 필요에 따라 다음 두 가지 모드 중 하나를 선택하세요:
- NIO 모드: 고복잡도 동시 접속에 적합. 아래와 같이
server.xml에 설정:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="250" minSpareThreads="30" acceptCount="150" />
- APR 모드: 운영체제의 네이티브 라이브러리를 활용해 성능을 극대화. 별도 설치 필요.
- JVM 가상 머신 파라미터 조정 JVM 설정은 메모리 관리와 가비지 컬렉션 성능에 결정적인 영향을 줍니다. 권장 설정은 다음과 같습니다:
JAVA_OPTS="-Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=150"
-Xms,-Xmx: 초기 및 최대 힙 크기 설정 → 메모리 확장 반복을 줄임-XX:+UseG1GC: 대용량 힙 환경에서 빠른 정리와 예측 가능한 일시 정지 시간 제공-XX:MaxGCPauseMillis: GC 일시 정지 시간 목표 → 응답 지연 감소
- 자원 스캔 최소화
애플리케이션 시작 시, Tomcat은 모든 JAR 파일을 스캔하여 태그 라이브러리(태그 라이브러리 정의) 및 어노테이션을 찾습니다. 불필요한 스캔을 제거하기 위해
catalina.properties에서 다음 항목을 설정합니다:
tomcat.util.scan.StandardJarScanFilter.jarsToSkip=commons-logging*.jar,logback*.jar,guava*.jar
이는 특히 많은 종속성 라이브러리가 포함된 프로젝트에서 시작 시간 단축과 메모리 절약에 효과적입니다.
도식: 컨테이너 초기화 단계에서 발생하는 클래스 로딩 및 자원 스캔 과정
- 캐싱 전략 적용 반복적인 요청 처리를 줄이기 위해 내장 캐싱 기능을 활성화합니다.
- 정적 리소스 캐싱:
<Context>
<Resources cachingAllowed="true" cacheMaxSize="204800" />
</Context>
→ 정적 파일(이미지, 스타일시트 등)의 재사용을 허용하고, 디스크 캐시 용량을 설정합니다.
- 세션 저장 전략:
PersistentManager를 사용해 세션 데이터를 파일 시스템 또는 외부 데이터베이스에 저장함으로써 메모리 누수를 방지합니다.
- 부하 테스트 도구 비교 성능 테스트를 위한 도구 선택은 목적에 따라 달라집니다.
- JMeter: 다중 프로토콜 지원(HTTP, HTTPS, JDBC 등), 쉬운 시나리오 작성, 보고서 생성 기능 강력
- Gatling: Scala 기반, 고성능, 장기간 지속 테스트에 적합
- Tomcat Manager:
/manager/status엔드포인트를 통해 실시간 서버 상태 모니터링 가능
- 종합적인 성능 모니터링 체계 구축 다양한 도구를 통합하여 실시간 모니터링을 구현하세요:
- JConsole / JVisualVM: JVM 내부 상태(메모리, 스레드, GC)를 실시간으로 확인
- Prometheus + Grafana:
JmxRemoteLifecycleListener를 활성화해 Tomcat 메트릭 수집 후 시각화 - ELK 스택(Elasticsearch, Logstash, Kibana):
catalina.out및localhost_access_log를 분석해 느린 요청이나 오류 패턴을 탐지
최종 요약: 성능 최적화의 반복적 접근 성능 개선은 단발성 작업이 아니라 지속적인 프로세스입니다. 다음과 같은 단계를 따르세요:
- 기준 성능 설정: 초기 성능 기준치 측정
- 단일 지표 최적화: 하나씩 파라미터 조정 후 효과 검증
- 생산급 부하 테스트: 실제 트래픽 시뮬레이션 수행
- 지속적 감시: 로그 및 모니터링 도구를 통한 성능 추적
이러한 전략을 통해 애플리케이션의 안정성과 반응성은 물론, 인프라 효율성도 크게 향상됩니다. 자세한 설정 방법은 공식 문서 webapps/docs/config/를 참조하시기 바랍니다.