반응형
에러 로그도 없는데 특정 시간대에 API가 느려진다. 이걸 어떻게 찾아야 할까. 지금까지 배운 OS 개념을 전부 연결하는 파트다.
1. 전형적인 장애 패턴
스케줄러 대용량 쿼리 실행
└── DB 커넥션 오래 점유
└── HikariCP 커넥션 풀 소진
└── 일반 API 요청들이 커넥션 대기
└── 스레드 점유 시간 길어짐
└── Tomcat Thread Pool 소진
└── 전체 API 느려짐 (에러는 없음)
에러가 없으니 로그만 봐선 원인을 못 찾는다. 스레드와 커넥션 풀 상태를 직접 봐야 한다.
2. Tomcat 스레드 풀 확인
Spring Actuator로 현재 스레드 상태를 볼 수 있다.
yaml
# application.yml
management:
endpoints:
web:
exposure:
include: metrics
GET /actuator/metrics/tomcat.threads.busy
GET /actuator/metrics/tomcat.threads.config.max
busy / max = 0.9 이상 → 스레드 풀 거의 소진
3. 스레드 덤프 - 스레드가 뭘 하다 묶였나
스레드 풀이 소진됐다면, 스레드가 정확히 어디서 대기 중인지 찍어봐야 한다.
bash
jps # 실행 중인 Java 프로세스 PID 확인
jstack {PID} # 스레드 덤프 출력
결과에서 이런 게 보이면 DB 커넥션 대기 중인 거다.
"http-nio-8080-exec-1" - WAITING
at sun.misc.Unsafe.park
at HikariPool.getConnection ← DB 커넥션 못 잡고 대기 중
4. HikariCP 커넥션 풀 확인
GET /actuator/metrics/hikaricp.connections.active
GET /actuator/metrics/hikaricp.connections.pending
pending > 0 → 커넥션 기다리는 스레드 있음
5. Tomcat 스레드 vs HikariCP 커넥션 비율
여기서 중요한 포인트가 있다.
Tomcat 스레드 200개
HikariCP 커넥션 10개 (기본값)
→ 요청 200개가 와도 DB 작업은 10개씩만 처리
→ 나머지 190개 스레드는 커넥션 기다리며 대기
→ 스레드 200개가 있어도 의미 없음
두 풀은 항상 같이 봐야 한다. 둘 중 하나만 크다고 해결이 안 된다.
HikariCP 권장 설정은 이렇다.
커넥션 수 = (CPU 코어 수 * 2) + 유효 디스크 수
ex) 4코어 서버 → 약 10개
커넥션 수를 무조건 늘린다고 좋은 게 아니다. DB 서버가 감당할 수 있는 커넥션 수에 한계가 있고, 무리하게 늘리면 DB 서버 부하가 증가해서 오히려 전체가 느려진다.
6. 모니터링 순서 정리
특정 시간대에 API가 느려지면 이 순서로 확인한다.
1. 해당 시간에 도는 스케줄러 있는지 확인
2. tomcat.threads.busy → 스레드 풀 얼마나 찼나
3. hikaricp.connections.pending → DB 커넥션 대기 있나
4. jstack으로 스레드 덤프 → 스레드가 정확히 뭘 하다 묶였나
반응형
'CS > OS' 카테고리의 다른 글
| OS 3편 - Race Condition, synchronized (feat. volatile) (0) | 2026.04.07 |
|---|---|
| OS 2편 - 동기 vs 비동기, 그리고 언제 써야 하는가 (0) | 2026.04.07 |
| OS 1편 - 프로세스, 스레드, Thread Pool (0) | 2026.04.07 |