이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- DB는 어떤 자원에서 한계에 부딪히는가?
- 서버를 늘렸는데 왜 DB가 먼저 터질 수 있는가?
- 백엔드 개발자는 DB 비용을 어떤 언어로 설명해야 하는가?
개요
DB 한계는 CPU 하나로 설명되지 않는다. 연결 수, I/O, 메모리, lock, log, replication, storage, network가 모두 한계가 될 수 있다. 애플리케이션 서버는 쉽게 늘릴 수 있지만, DB는 공유 상태를 가진 시스템이라 수평 확장이 어렵다.
백엔드 개발자는 기능 개발 시 DB 비용을 예상하고, 장애 시 어떤 자원이 병목인지 분리해야 한다.
원리
DB 비용은 “쿼리 한 번이 몇 ms인가”만으로 판단할 수 없다. 같은 30ms 쿼리라도 초당 1번 호출되면 문제가 작고, 초당 2,000번 호출되면 DB 전체를 밀어낼 수 있다. 반대로 2초짜리 쿼리라도 관리자 기능에서 하루 한 번 replica에서 실행하면 허용될 수 있다.
백엔드 개발자는 단일 실행 시간, 호출 빈도, 동시성, 읽은 row 수, 정렬/조인 비용, lock 대기, 결과 크기, 로그 생성량을 함께 본다. 이 조합이 DB의 CPU, I/O, memory, connection, lock, network, replication 한계 중 어디를 압박하는지 설명할 수 있어야 한다.
주요 한계
DB에서 자주 만나는 한계는 다음이다.
- CPU: 조인, 정렬, 집계, 함수 계산
- I/O: 테이블 스캔, 인덱스 랜덤 접근, checkpoint
- Memory: buffer cache, sort memory, connection memory
- Connection: max connections, pool 고갈
- Lock: row/table/gap/metadata lock
- Log: WAL/binlog 증가
- Replication: replica lag
- Storage: bloat, index size, backup size
- Network: DB 왕복 횟수, 큰 result set, cross-region latency
느린 API 하나도 이 중 여러 원인이 섞일 수 있다.
서버 확장과 DB 병목
애플리케이션 인스턴스를 2대에서 10대로 늘리면 DB로 들어가는 동시 쿼리와 커넥션도 늘어난다.
pool 10 x 2대 = 최대 20 connections
pool 10 x 10대 = 최대 100 connections웹 서버 CPU는 여유가 생겨도 DB는 더 많은 동시 쿼리를 처리해야 한다. 느린 쿼리나 lock 경합이 있으면 확장은 오히려 장애를 키울 수 있다.
비용 모델
SQL 비용은 대략 다음 요소로 생각한다.
- 몇 행을 읽는가?
- 어떤 인덱스를 쓰는가?
- 정렬이나 해시 집계가 필요한가?
- 조인 중간 결과가 얼마나 큰가?
- 락을 얼마나 기다리는가?
- 결과를 얼마나 많이 전송하는가?
- 얼마나 자주 호출되는가?
백엔드 리뷰에서 “이 쿼리는 느릴 것 같아요”보다 “이 쿼리는 status 조건이 낮은 선택도이고, created_at 정렬 인덱스가 없어 많은 row sort가 발생할 수 있습니다”라고 말해야 한다.
증상과 원인을 연결할 때는 다음처럼 가설을 세운다.
| 증상 | 먼저 의심할 것 |
|---|---|
| DB CPU가 높다 | full scan, 비싼 join, sort, aggregate, 함수 계산 |
| CPU는 낮은데 latency가 높다 | lock wait, I/O wait, network, pool 대기 |
| pool pending이 증가한다 | slow query, 긴 transaction, pool 과소/과대 설정, DB max connections |
| replica lag가 증가한다 | write spike, 대량 DML, index 추가, checkpoint/I/O 부하 |
| 특정 row에서만 지연된다 | hot row, 순번 채번, 재고/포인트 같은 집중 update |
이 표는 정답표가 아니라 대화의 시작점이다. 인프라/DBA가 보는 지표와 백엔드가 아는 기능 맥락을 합쳐야 원인이 좁혀진다.
실전 팁
- API별 DB 호출 수와 호출 빈도를 본다.
- p95/p99 지연은 평균보다 중요하다.
- 서버 확장 전 DB 총 연결 수와 slow query를 점검한다.
- 대형 기능 출시 전 데이터 증가량과 인덱스를 예상한다.
- DB 비용은 인프라/DBA와 공유 가능한 지표로 말한다.
- “단일 쿼리 시간 x 호출 빈도 x 동시성”으로 기능의 DB 예산을 거칠게라도 계산한다.
- 장애 중에는 tuning보다 먼저 트래픽 제한, batch 중단, timeout 조정, 읽기 경로 차단처럼 피해 확산을 줄일 선택지를 검토한다.
위험 신호!
- DB CPU만 보고 lock wait를 놓친다.
- 서버를 늘리면 DB도 자동으로 버틸 것이라 생각한다.
- connection 수를 계산하지 않고 오토스케일링한다.
- 쿼리 호출 빈도를 보지 않고 평균 실행 시간만 본다.
- replica lag를 읽기 확장의 당연한 부작용으로만 방치한다.
- 애플리케이션 서버 scale-out을 DB 연결 총량 증가로 환산하지 않는다.
- lock wait를 DB 성능 문제로만 보고 긴 transaction을 만든 코드 경로를 추적하지 않는다.
확인 질문
- DB 한계를 CPU만으로 설명하면 부족한 이유는 무엇인가?
- DB는 연결 수, I/O, lock, memory, log, replication, storage 등 다양한 자원에서 병목이 생기기 때문이다.
- 애플리케이션 서버 확장이 DB 장애를 키울 수 있는 이유는 무엇인가?
- 서버 수가 늘면 DB로 들어가는 동시 연결과 쿼리도 늘어 공유 병목을 더 세게 압박하기 때문이다.
- SQL 비용을 설명할 때 봐야 할 요소는 무엇인가?
- 읽는 행 수, 인덱스, 정렬/집계, 조인 중간 결과, 락 대기, 결과 크기, 호출 빈도다.
- 평균 쿼리 시간이 낮아도 운영 장애가 날 수 있는 이유는 무엇인가?
- 호출 빈도와 동시성이 높거나 p99 지연, lock wait, pool 대기가 커지면 평균은 낮아도 사용자 요청과 DB 전체가 밀릴 수 있기 때문이다.