CS/OS

OS 4편 - 실무 병목 찾기

isTrue 2026. 4. 8. 00:18
반응형

에러 로그도 없는데 특정 시간대에 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으로 스레드 덤프 → 스레드가 정확히 뭘 하다 묶였나

 

반응형