이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- DB 장애가 발생했을 때 백엔드 개발자는 무엇을 먼저 해야 하는가?
- 원인 분석보다 먼저 해야 하는 완화 조치는 무엇인가?
- 장애 회고에는 어떤 DB 증거를 남겨야 하는가?
개요
DB 장애 상황에서 백엔드 개발자의 첫 임무는 범인을 맞히는 것이 아니다. 영향 범위를 줄이고, 증거를 모으며, 인프라/DBA와 같은 언어로 상황을 공유하는 것이다.
장애 중에는 정확성보다 순서가 중요하다. 원인 분석을 하느라 유입 차단과 배치 중지를 놓치면 장애가 커진다.
원리
DB 장애 대응의 원리는 원인 추측보다 시스템 압력을 낮추고 관측 가능한 사실을 공유하는 것이다. DB 장애는 느린 쿼리 하나가 아니라 재시도, pool 대기, lock wait, batch, 배포 변경이 서로 증폭하며 커지는 경우가 많다.
백엔드 개발자는 “내 코드가 원인인가 아닌가”를 방어하기보다 어떤 요청을 줄일 수 있고, 어떤 작업을 멈출 수 있으며, 어떤 데이터가 반드시 보존되어야 하는지를 빠르게 제공해야 한다.
상황
다음 알림이 동시에 왔다.
API p99 latency > 10s
Hikari connection timeout 증가
DB active sessions 급증
일부 주문 API 500 증가이 상황에서 바로 DB 재시작을 요구하거나 pool size를 늘리면 위험하다. 먼저 전체 장애인지 특정 기능 장애인지 나눈다.
먼저 확인할 것
- 읽기 API와 쓰기 API 중 어디가 실패하는가?
- 전체 DB가 느린가, 특정 테이블/쿼리만 느린가?
- active connection과 pending acquire는 어떤가?
- lock wait와 blocking transaction이 있는가?
- 최근 배포, migration, batch, 이벤트가 있었는가?
- DB CPU/I/O가 포화인가?
- replica lag가 있는가?
- 사용자가 실제로 겪는 영향은 무엇인가?
즉시 완화
완화 조치는 원인별로 다르지만, 공통 원칙은 유입과 점유 시간을 줄이는 것이다.
- 비핵심 batch를 중지한다.
- 관리자 대량 다운로드를 차단한다.
- 문제가 되는 endpoint를 rate limit 한다.
- 재시도 폭주를 줄인다.
- 캐시 가능한 읽기를 캐시로 우회한다.
- 안전하게 판단된 long query를 종료한다.
- 신규 배포를 멈추고 변경 동결을 선언한다.
운영에서 query kill은 신중해야 한다. 어떤 트랜잭션을 죽이면 롤백이 오래 걸릴 수 있고, 사용자 작업이 실패할 수 있다. DBA와 함께 blocking 관계와 영향 범위를 본다.
완화 조치는 반드시 기대 지표와 함께 실행한다.
| 조치 | 기대 지표 |
|---|---|
| batch 중지 | DB write I/O, lock wait, replica lag 감소 |
| endpoint rate limit | active session, pool pending, p99 감소 |
| 재시도 차단 | 요청 수, error amplification 감소 |
| cache 우회 또는 cache 강제 | read query 호출량 감소 |
| blocking query 종료 | lock wait 감소, 관련 API 회복 |
조치를 했는데 기대 지표가 움직이지 않으면 가설을 바꿔야 한다.
백엔드 개발자가 가져갈 자료
인프라/DBA에게 다음 형태로 전달한다.
13:05부터 주문 생성 API p95가 300ms에서 8s로 증가했습니다.
동시에 Hikari pending acquire가 0에서 80으로 증가했습니다.
13:00에 쿠폰 backfill 배치가 시작됐습니다.
문제 API의 주요 SQL은 orders insert 후 coupon_issues update입니다.
현재 사용자 영향은 주문 생성 지연과 일부 timeout입니다.이 정도가 있으면 DBA는 DB 내부 지표와 연결하기 쉽다.
장애 중 상태 공유는 짧고 반복 가능해야 한다.
현재 영향: 주문 생성 p99 10s, timeout 4%
완화: 쿠폰 backfill 중지 완료, 주문 API rate limit 적용 준비
DB 단서: active session 180, lock wait 증가
다음 확인: blocking transaction과 최근 배포 SQL 확인이런 형식은 개발자, 인프라, PM, CS가 같은 상황판을 보게 만든다.
원인별 대응 힌트
Lock wait가 주원인이면:
- blocking transaction을 찾는다.
- 긴 트랜잭션 코드 경로를 확인한다.
- 쿼리 조건 인덱스가 없어 넓은 범위를 잠그는지 본다.
- 배치와 사용자 API의 충돌을 분리한다.
Connection pool 고갈이 주원인이면:
- 커넥션을 오래 잡는 쿼리와 트랜잭션을 찾는다.
- 외부 API 호출이 트랜잭션 안에 있는지 본다.
- pool size가 총 DB 연결 예산을 초과하지 않는지 본다.
- timeout과 재시도 정책을 조정한다.
DB CPU가 주원인이면:
- 상위 쿼리와 호출 빈도를 본다.
- 정렬, 집계, full scan을 확인한다.
- 캐시나 rate limit으로 읽기 부하를 줄인다.
- 인덱스 추가는 즉시 가능한지 신중하게 본다.
실전 팁
- 장애 중에는 원인 추측보다 영향 범위와 유입 제어를 먼저 한다.
- 최근 배포, migration, batch, 이벤트 트래픽을 한 화면에서 본다.
- query kill은 DBA와 blocking 관계를 확인한 뒤 신중하게 판단한다.
- 장애 완화 조치마다 어떤 지표가 좋아져야 하는지 정한다.
- 회고에는 SQL, 실행 계획, pool 지표, lock 지표를 남긴다.
- 장애 중 상태 공유는 영향, 조치, 지표, 다음 확인으로 짧게 반복한다.
- 조치 하나를 적용한 뒤 기대 지표가 변했는지 보고 다음 조치로 넘어간다.
- 데이터 손실 가능성이 있는 조치는 비즈니스 책임자와 복구 담당자를 같이 세운다.
장애 회고에 남길 것
장애 회고에는 다음 증거가 있어야 한다.
- 타임라인
- 사용자 영향
- 주요 SQL과 실행 계획
- DB 지표 스냅샷
- 커넥션 풀 지표
- lock wait 또는 deadlock 로그
- 배포/배치 이력
- 즉시 완화 조치
- 근본 해결 조치
- 재발 방지 알림
회고가 “인덱스 추가함”으로 끝나면 부족하다. 왜 그 인덱스가 필요했고, 왜 기존 구조에서 놓쳤으며, 다음에 어떻게 감지할지까지 남겨야 한다.
주니어 팁
장애 중에는 혼자 해결하려고 하지 않는다. 대신 정확한 관찰을 짧게 공유한다.
지금 제가 확인한 것은 세 가지입니다.
1. 주문 생성 API만 느립니다.
2. Hikari connection timeout이 증가했습니다.
3. 13시에 시작한 배치가 같은 테이블을 업데이트합니다.이런 공유가 추측보다 훨씬 도움이 된다.
시니어 팁
시니어는 장애 상황에서 의사결정 순서를 관리한다.
- 영향 범위 확인
- 유입 제한
- 증거 보존
- 원인 격리
- 임시 복구
- 근본 개선
모든 조치를 한 번에 하지 않는다. 각 조치가 어떤 지표를 개선해야 하는지 확인하며 진행한다.
Guru급 팁
DB 장애는 종종 여러 작은 결정의 합이다. 긴 트랜잭션, 느슨한 timeout, 큰 pool, 즉시 재시도, 대량 배치, 부족한 인덱스가 평소에는 괜찮다가 이벤트 트래픽에서 동시에 터진다. 고급 대응은 한 가지 원인을 찾는 것이 아니라 증폭 고리를 끊는 것이다.
위험 신호!
- 장애 중 신규 배포와 배치를 계속 진행한다.
- pool size 변경만 반복한다.
- query kill의 롤백 비용을 고려하지 않는다.
- 재시도 폭주와 rate limit을 확인하지 않는다.
- 회고가 “인덱스 추가” 한 줄로 끝난다.
- 여러 완화 조치를 동시에 적용해 무엇이 효과였는지 알 수 없다.
- 사용자 영향과 데이터 손실 가능성을 기술 지표 뒤에 숨긴다.
확인 질문
- DB 장애 중 백엔드 개발자의 첫 임무는 무엇인가?
- 영향 범위를 줄이고 증거를 모아 원인 격리와 협업이 가능하게 만드는 것이다.
- query kill을 신중해야 하는 이유는 무엇인가?
- 롤백이 오래 걸리거나 사용자 작업을 실패시키고, 잘못된 쿼리를 죽이면 더 큰 장애를 만들 수 있기 때문이다.
- 장애 회고에 실행 계획을 남겨야 하는 이유는 무엇인가?
- 쿼리 병목의 원인과 개선 효과를 재현 가능한 증거로 남기기 위해서다.
- 장애 완화 조치를 적용할 때 기대 지표를 정해야 하는 이유는 무엇인가?
- 조치가 실제로 병목을 줄였는지 확인하고, 효과가 없으면 다음 가설로 빠르게 전환하기 위해서다.