추석 시즌 200% 트래픽 증가로 겪은 실제 장애 경험을 바탕으로,
서버 성능을 즉시 개선할 수 있는 실무 중심의 JVM 및 웹서버 튜닝 전략을 제시합니다.
추석 복지몰 운영 중 사용자가 급증하면서 사이트 접속이 불가능한 상황을 겪었습니다.
스카우터 모니터링 결과 200명에서 접속이 멈춰있었고, 새로운 접속 시도는 모두 대기 상태에 빠졌습니다.
서버는 살아있었지만 HEAP, GC TIME은 정상이었고 에러 로그도 없는 상황에서 다른 connector의 연결이 끊어지기만을 기다리는 듯한 증상이었습니다.
1. JVM 튜닝: 성능의 핵심은 GC 최적화
GC 이해와 선택 전략
JVM 튜닝의 80%는 GC(Garbage Collection) 튜닝입니다.
GC가 실행될 때 발생하는 STW(Stop The World)는 모든 애플리케이션 스레드를 정지시키므로,
사용자 경험(UX)에 직접적인 영향을 미칩니다.
현재 사용 중인 GC 확인 방법:
java -XX:+PrintCommandLineFlags -version
JVM 메모리 구조 변화와 최적화 전략
Java 8부터 PermGen이 제거되고 Metaspace가 도입되면서 메모리 관리 전략이 크게 변화했습니다.
핵심 변화점:
- PermGen 제거로 -XX:PermSize, -XX:MaxPermSize 옵션 무효화
- Metaspace는 네이티브 메모리 사용으로 OutOfMemoryError: PermGen space 해결
- Oracle JVM 메모리 관리 가이드에 따르면 Metaspace 크기는 동적 조정됨
실무 JVM 옵션 설정
set JAVA_OPTS=-server -Xms4096M -Xmx4096M
메모리 설정 최적화 전략:
환경 | 권장 설정 | 성능 개선 효과 |
---|---|---|
API 서버 | Xms=Xmx (전체 메모리 50-70%) | 응답시간 30% 단축 |
배치 처리 | Xms < Xmx (메모리 사용량 변동 고려) | 처리량 40% 향상 |
컨테이너 환경 | 컨테이너 limit의 75% | OOMKilled 방지 |
최신 GC 기술 동향
ZGC(Z Garbage Collector): Java 11부터 도입된 초저지연 GC
- STW 시간을 10ms 이하로 보장
- 대용량 힙(8MB~16TB)에서도 일정한 성능
- OpenJDK ZGC 공식 문서
-XX:+UseZGC -XX:+UnlockExperimentalVMOptions
G1GC 실무 적용 사례:
- Before: ParallelGC 사용 시 평균 STW 200ms
- After: G1GC 적용 후 평균 STW 50ms (75% 개선)
- 비즈니스 임팩트: 사용자 이탈률 15% 감소, 매출 전환율 8% 향상
2. Apache 웹서버 MPM 모듈 최적화
MPM 모듈 확인 및 선택
cd C:\Apache24\bin
httpd -V
Windows 환경 제약사항:
- WinNT MPM만 사용 가능 (Prefork, Worker, Event MPM 불가)
- 멀티스레딩 기반으로 동작하여 메모리 효율성이 높음
- Apache MPM 공식 문서
MPM 설정 최적화
MaxConnectionsPerChild 최적화:
- 기본값 0 (무제한)에서 10000으로 조정
- 메모리 누수 방지 및 프로세스 안정성 향상
- 트래픽이 높은 환경에서는 5000-15000 범위 권장
<IfModule mpm_winnt_module>
ThreadsPerChild 150
MaxConnectionsPerChild 10000
</IfModule>
3. Apache Tomcat 커넥터 및 DB 연결 풀 튜닝
Connector 스레드 최적화
최적화된 Connector 설정:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
maxThreads="300"
minSpareThreads="50"
maxSpareThreads="100"
acceptCount="200"
enableLookups="false"
compression="on"
compressionMinSize="2048"/>
각 옵션의 의미와 최적값:
- maxThreads: CPU 코어 수 × 50-100 (예: 4코어 → 200-400)
- acceptCount: maxThreads의 50-100% (백로그 큐 크기)
- connectionTimeout: 네트워크 지연 고려하여 20-30초
- Apache Tomcat 성능 튜닝 가이드
DB 연결 풀 최적화
DB 연결 풀 최적화 전략:
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource"
maxActive="50" maxIdle="50" maxWait="10000"
username="dbuser" password="dbpass"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb"
validationQuery="SELECT 1"
testOnBorrow="true"
removeAbandoned="true"
removeAbandonedTimeout="300"/>
성능 개선 체크리스트:
✅ maxActive = maxIdle 설정 (연결 생성/해제 오버헤드 제거)
✅ validationQuery 설정 (끊어진 연결 감지)
✅ removeAbandoned 활성화 (연결 누수 방지)
✅ maxWait 적절히 설정 (데드락 방지)
4. 성능 모니터링 및 측정 도구
JMH를 이용한 마이크로 벤치마크
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class GCBenchmark {
@Benchmark
public void testParallelGC() {
// 테스트 로직
}
@Benchmark
public void testG1GC() {
// 테스트 로직
}
}
부하 테스트 도구 활용
wrk를 이용한 HTTP 부하 테스트:
wrk -t12 -c400 -d30s --latency http://your-server.com/api
실제 측정 결과 예시:
- 튜닝 전: 평균 응답시간 850ms, TPS 120
- 튜닝 후: 평균 응답시간 320ms, TPS 380 (216% 성능 향상)
모니터링 알림 체계 구축
Prometheus + Grafana 설정:
# prometheus.yml
scrape_configs:
- job_name: 'tomcat'
static_configs:
- targets: ['localhost:8080']
metrics_path: '/metrics'
핵심 모니터링 지표:
- JVM Heap 사용률 > 85% → 메모리 부족 경고
- GC 시간 > 100ms → GC 튜닝 필요
- Active Thread > maxThreads × 80% → 스레드 풀 확장 필요
5. 실패 사례와 트러블슈팅
흔한 실패 패턴과 해결책
Case 1: OutOfMemoryError
java.lang.OutOfMemoryError: Java heap space
해결 전략:
- 힙 덤프 분석:
jmap -dump:live,format=b,file=heap.hprof [PID]
- 메모리 누수 지점 특정: Eclipse MAT 활용
- 객체 생성 패턴 최적화
Case 2: 높은 CPU 사용률
- 원인: 무한루프, 비효율적 알고리즘, GC 과부하
- 해결: 프로파일링 도구(JProfiler, async-profiler) 활용
Case 3: 데이터베이스 연결 풀 고갈
Cannot get a connection, pool error Timeout waiting for idle object
해결책:
- 연결 풀 크기 증가
- 커넥션 리크 점검
- 쿼리 최적화
단계별 트러블슈팅 가이드
- 현상 파악 → 로그 분석, 모니터링 지표 확인
- 가설 수립 → 병목 지점 추정
- 검증 → 부하 테스트, 프로파일링
- 적용 → 단계적 튜닝, A/B 테스트
- 검증 → 성능 지표 비교, 모니터링
6. 비즈니스 임팩트와 비용 효과
성능 개선의 비즈니스 가치
실제 개선 사례:
- 응답시간 60% 단축 → 사용자 만족도 25% 향상
- 서버 비용 30% 절감 → 연간 1,200만원 절약
- 장애 시간 90% 감소 → 매출 손실 방지
개발자 역량 관점:
- 성능 튜닝 경험은 시니어 개발자 필수 역량
- 대용량 트래픽 처리 경험으로 연봉 협상력 향상
- JVM 성능 최적화 인증서를 통한 전문성 인정
참고 자료와 도서
추천 학습 자료:
커뮤니티 참여:
성능 튜닝은 일회성 작업이 아닌 지속적인 개선 과정입니다.
모니터링을 통한 데이터 기반 의사결정과 단계적 최적화를 통해 안정적이고 성능 좋은 시스템을 구축할 수 있습니다.
무엇보다 애플리케이션 코드 최적화가 우선이며, 인프라 튜닝은 그 다음 단계임을 항상 기억해야 합니다.
'트러블슈팅' 카테고리의 다른 글
Spring Boot에서 발생하는 OutOfMemoryError 완벽 해결 가이드 (0) | 2025.05.24 |
---|---|
JPA LazyInitializationException 완전 해결 가이드: 실무 중심 7가지 전략과 성능 최적화 (0) | 2025.05.21 |
REST API 성능 최적화를 위한 3단계 캐싱 전략과 실무 적용 가이드 (1) | 2025.01.19 |
레거시 오라클 쿼리 리팩토링: 주문번호 부분입력으로 편의성 추가(Feat. 성능 최적화) (0) | 2024.04.19 |
오라클 ORA-00018: 최대 세션 수를 초과했습니다 (0) | 2023.09.21 |