Spring Boot 성능 병목 원인 찾기: 스레드·DB·GC 분석
스레드 덤프, 데이터베이스 대기, GC 로그를 결합해 Spring Boot 애플리케이션의 성능 병목을 단계적으로 진단하고 원인 분류를 제시하는 방법론
목차
개요
Spring Boot 서비스에서 응답 지연이나 CPU 사용률 급증 같은 문제가 발생하면 원인 파악이 우선이다. 성능 병목은 주로 스레드 경쟁, DB 지연, 또는 GC 활동으로 발생한다. 본문은 spring boot 성능 병목 분석 관점에서 스레드·DB·GC를 순차적으로 살펴보는 방법을 정리한다. 처음 접하는 개발자도 이해할 수 있도록 절차와 해석 포인트를 중심으로 설명한다.
진단 전 준비 사항
문제 발생 시점의 환경 정보와 로그를 확보하면 분석 효율이 높아진다. 다음 항목을 먼저 수집한다.
- 문제가 발생한 JVM 프로세스 ID
- 애플리케이션 로그와 DB 슬로우 로그 타임스탬프
- 모니터링 지표(CPU, 메모리, GC, 스레드 수)
스레드 분석 (spring boot thread dump 분석)
스레드 덤프는 동시성 문제와 블로킹 지점을 찾을 때 핵심 정보다. 스레드 상태와 호출 스택을 통해 어디에서 대기하는지 확인한다.
덤프 수집 방법
jstack <pid> > threaddump.txt
jcmd <pid> Thread.print > threaddump.txt
덤프는 여러 시점(예: 3회, 5초 간격) 수집하면 일시적 대기인지 지속적 병목인지 판별에 도움이 된다.
해석 포인트
- BLOCKED 상태가 많은 경우: 락 경쟁(Lock) 가능성.
- WAITING 또는 TIMED_WAITING: 외부 리소스 응답 대기나 스케줄링 문제.
- RUNNABLE이지만 CPU 사용률 저조: I/O 대기나 네이티브 호출 가능성.
- 동일한 메서드에서 다수 스레드가 대기하면 그 지점이 주요 후보.
예시 스택 패턴
"http-nio-8080-exec-1" #12 prio=5 os_prio=0 tid=0x00007f... RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
위 패턴은 네트워크/DB 호출의 블로킹을 시사한다. spring boot thread dump 분석 과정에서 호출 계층을 따라가면 실제 블로킹 지점이 보인다.
데이터베이스 병목 점검
DB 관련 지연은 애플리케이션 응답 지연의 대부분을 차지한다. 연결 풀 고갈, 느린 쿼리, 인덱스 부재를 우선 점검한다.
체크리스트
- 커넥션 풀 사용량(활성/대기) 확인
- 슬로우 쿼리 로그 점검
- 인덱스 및 실행 계획(EXPLAIN) 확인
- 트랜잭션 길이와 잠금(Lock) 여부 확인
대표 명령 예시
-- MySQL
SHOW FULL PROCESSLIST;
-- PostgreSQL
SELECT pid, state, query, now() - query_start AS duration FROM pg_stat_activity WHERE state 'idle';
연결 풀 고갈이 의심되면 HikariCP 같은 커넥션 풀의 activeCount, idleCount 지표를 확인한다. 커넥션 반환이 늦다면 애플리케이션 레벨의 DB 호출 코드나 트랜잭션 범위를 점검한다.
GC 분석 (gc 분석 spring boot)
GC는 메모리 회수 과정에서 애플리케이션 지연을 유발할 수 있다.频繁한 풀 GC 또는 긴 Stop-the-world가 문제다. GC 로그와 JVM 메트릭을 분석하면 원인을 좁힐 수 있다.
로그 활성화 및 기본 명령
-XX:+UseG1GC -Xlog:gc*,gc+heap=info:file=gc.log:time,uptime,level -Xms2g -Xmx2g
jstat -gcutil <pid> 1000 10
jstat는 실시간 힙 사용과 GC 활동 비율을 보여준다. G1을 사용 중이면 Full GC 빈도와 Young/Old 영역의 사이즈를 확인한다.
해석 포인트
- Young GC가 매우 잦으면 객체 생성률이 높거나 프로듀서가 과도함.
- Old 영역이 빠르게 증가하면 장기 객체 누수 가능성.
- Full GC 또는 긴 Stop-the-world는 메모리 설정 및 GC 튜닝 필요.
상호 상관관계 파악
스레드, DB, GC는 독립적이지 않다. 예를 들어 DB 지연은 스레드 대기를 유발하고, 대기 중인 객체 축적은 GC 부담을 높인다. 다음 절차로 원인을 좁힌다.
- 문제 시점의 스레드 덤프와 GC 로그 타임스탬프 비교
- DB 슬로우 로그의 쿼리 시작/종료 시간을 덤프와 대조
- 모니터링 지표로 CPU, 힙, GC 빈도, 스레드 수 변화를 시계열로 확인
사례별 단서와 대응 방향
- 스레드가 DB 대기 중이면 쿼리 최적화와 커넥션 풀 조정이 우선.
- 스레드 락 경쟁이면 코드의 동기화 범위 축소와 락 분리 고려.
- GC 영향이 크면 힙 사이즈 재설정, GC 알고리즘 교체, 객체 생명주기 개선 검토.
결론
spring boot 성능 병목 분석은 스레드, DB, GC를 각각 수집하고 교차 비교하는 절차가 핵심이다. 단계별 로그 확보와 모니터링 지표 비교로 원인을 좁히면 실질적인 개선 작업이 가능하다. 문제 재현 환경이 허용되면 변경을 소규모로 적용하고 지표로 효과를 검증하는 방식이 권장된다.