DB 부하 vs App 부하를 나누는 기준은 “병목이 데이터 접근 계층(I/O, 락, 플랜) 에 있냐, 아니면 애플리케이션 계층(CPU, GC, 스레드, 외부호출) 에 있냐”로 쪼개면 됩니다. 실무에서는 아래 체크리스트로 거의 판별돼요.
1) 지표로 1차 분류 (가장 확실)
DB 부하 쪽 신호
DB CPU가 높고, slow query / p95 쿼리시간이 튐
connections 증가 + lock wait, deadlock, buffer/cache miss, IO wait 상승
특정 테이블/인덱스가 핫스팟(인덱스 스캔 폭증, Full Scan, Sort/Hash Spill)
App은 “DB 응답 기다리느라” 스레드가 묶임 (thread dump에 JDBC wait 다수)
App 부하 쪽 신호
App CPU 높음, DB 쿼리는 빠른데 전체 API 응답이 느림
GC 시간/빈도 증가, heap pressure, allocation rate 폭증
스레드 풀 고갈(서버 worker/thread pool, async queue, connection pool은 여유인데 app 스레드가 바쁨)
직렬화/역직렬화(JSON), 템플릿 렌더링, 암호화/압축, 대용량 객체 생성이 원인
외부 API 호출(latency) 때문에 app에서 대기(HTTP client wait)가 많음
2) “시간 분해”로 나누기 (APM/로그로 쪼개면 끝)
요청 1건을 아래로 쪼개서 비율을 보면 됩니다.
T_total = T_app + T_db + T_external + T_queue
여기서 T_db(쿼리 수행 + 결과 전송)가 p95의 대부분이면 DB 부하
T_app(비즈니스 로직/변환/검증/렌더링/암호화)가 대부분이면 App 부하
실무 팁: SQL 실행시간(ms) + rows + 호출횟수 를 요청 단위로 남기면 “DB가 문제인지, 호출을 너무 많이 하는지(N+1)”가 바로 보여요.
3) 병목 형태로 구분 (패턴)
DB가 병목인 대표 패턴
트래픽 증가에 따라 쿼리 시간도 같이 증가(락/IO/플랜 문제)
“동일 데이터”를 많이 조회/갱신(핫로우) → 락 대기
인덱스 부재/잘못된 조건 → Full Scan
트랜잭션 길게 잡음 → 락 장기화
App이 병목인 대표 패턴
DB는 여유인데 WAS CPU/GC가 먼저 터짐
객체 매핑/JSON 변환/대용량 리스트 처리로 CPU 소모
동기 외부호출이 많아 스레드 대기 증가(타임아웃/재시도 폭증)
로깅 과다(특히 debug, 큰 payload 출력)
4) “풀 고갈”로 더 명확히 보기
DB Connection Pool 고갈(active=max, wait time 증가) + DB 쿼리 느림 ⇒ DB 병목 또는 쿼리/트랜잭션 설계 문제
서버 스레드 풀 고갈(Tomcat threads busy) + DB는 빠름 ⇒ App/외부호출/락(앱단 synchronized 등) 병목
5) 결론적으로 쓰는 실무 기준 한 줄
DB 부하: “DB에서 시간이 소비된다(쿼리/락/IO/플랜).”
App 부하: “DB 밖에서 시간이 소비된다(CPU/GC/스레드/외부호출/변환).”
'스프링 개발자 > Spring & Backend' 카테고리의 다른 글
| 시스템 콜이란 무엇인가요? (0) | 2025.12.18 |
|---|---|
| CPU 스케줄링에 대해서 설명해주세요. (0) | 2025.12.17 |
| 디스크 접근 시간에 대해서 설명해주세요. (0) | 2025.12.15 |
| 해시 충돌에 대해서 설명해주세요. (0) | 2025.12.12 |
| 교착 상태에 대해서 설명해주세요 (0) | 2025.12.09 |