LLM WikiAccess-protected knowledge portal
← 스터디 홈
2편 · 약 20분

장애 분류와 SLO: 접속 장애, 지연, 데이터 손상, 복제 지연

모든 DB 장애는 같지 않다

"DB가 이상해요"라는 알림이 들어왔을 때, 가장 먼저 해야 할 일은 그 이상함이 어느 범주인지 구분하는 것이다. 접속 자체가 안 되는 것, 접속은 되는데 응답이 느린 것, 응답은 오는데 데이터가 이상한 것, 복제본에서 읽은 데이터가 주서버보다 과거를 보여주는 것은 각각 원인도 다르고, 긴급도도 다르고, 완화 방법도 다르다.

장애 범주를 미리 정의해두지 않으면 세 가지 문제가 생긴다.

  • 처음 장애를 보는 사람이 무엇부터 확인해야 할지 모른다.
  • SLO를 어디에 걸어야 하는지, 알림 임계값이 맞는지 판단이 안 된다.
  • 사후 분석에서 장애 유형이 통일되지 않아 추세를 볼 수 없다.

이 장에서는 DB 장애를 네 범주로 정리하고, 각 범주에 맞는 SLI·SLO, 대표 원인, 완화 방법을 다룬다.


DB 장애 분류 체계

접속 장애 Connection refused
Pool exhaustion
Auth failure
DNS/LB 이상
SLI: 연결 성공률
SLO: ≥ 99.9%
지연 장애 Slow query
Lock contention
IOPS 병목
Connection storm
SLI: p99 쿼리 지연
SLO: ≤ 100ms
데이터 손상 Checksum 실패
Torn page
WAL/binlog 손상
사람 실수(DROP)
SLI: 무결성 이벤트
SLO: 0건/월
복제 지연 Replica lag 급증
Apply 병목
Split-brain
replica 탈락
SLI: replica lag (초)
SLO: ≤ 30초 99%
장애 범주를 먼저 확정하면 → 올바른 SLI를 선택하고 → 의미 있는 SLO를 설정할 수 있다
DB 장애 분류 체계와 SLO 연결

범주 1: 접속 장애

접속 장애는 애플리케이션이 DB에 새 연결을 맺지 못하거나, 기존 연결이 끊어지는 상황이다. 사용자 관점에서는 로그인 실패, API 500 오류, "DB 연결 실패" 메시지로 나타나는 경우가 많다.

주요 원인

원인구체 증상확인 포인트
Connection pool 고갈앱에서 "pool timeout"DB 활성 연결 수, 앱 pool 설정
max_connections 초과DB에서 "too many connections"SHOW STATUS LIKE 'Threads_connected'
네트워크/DNS 장애타임아웃, 패킷 손실ping, traceroute, DNS TTL
인증 실패"Access denied for user"계정·비밀번호·호스트 허용 설정
TLS 인증서 만료SSL handshake 오류인증서 만료일
primary 장애, LB 미전환failover 후에도 연결 안 됨LB/HA 구성, DNS 전파 시간

SLI와 SLO 설정 가이드

접속 장애의 SLI는 연결 성공률이다.

연결 성공률 = (성공한 연결 시도 수) / (전체 연결 시도 수)

SLO 예:

  • Tier-1 서비스 DB: 연결 성공률 ≥ 99.9% (4.38분/월 허용)
  • Tier-2 서비스 DB: 연결 성공률 ≥ 99.5%

접속 장애는 보통 완전한 서비스 중단으로 이어지므로 알림 임계값을 낮게 유지하는 것이 좋다. 연결 성공률이 5분 이상 99% 아래로 떨어지면 P1 알림으로 분류한다.

Connection storm 패턴

Connection storm은 접속 장애의 전형적 양상이다. 다음 순서로 진행된다.

  1. DB 재시작 또는 failover 발생
  2. 앱 서버들이 동시에 재연결 시도
  3. max_connections 또는 OS의 accept queue를 순간 초과
  4. 연결 성공도 실패도 아닌 ETIMEDOUT 폭증
  5. 앱이 에러를 내면서 재시도 → 연결 폭증 반복

완화 방법: connection pool의 reconnect 로직에 지수 백오프jitter를 추가해 동시 재연결을 분산시킨다. DB 앞에 ProxySQL·PgBouncer 같은 connection proxy를 두면 앱이 DB를 직접 보지 않아 storm 충격을 흡수할 수 있다.


범주 2: 지연 장애

지연 장애는 연결은 성공하지만 쿼리 또는 트랜잭션이 기대보다 오래 걸리는 상태다. 서비스가 완전히 죽지는 않지만 사용자 경험이 나빠지고, 악화되면 timeout으로 인한 오류로 발전한다.

주요 원인

쿼리 레이어:

  • 인덱스 미사용, full table scan
  • 통계 정보 부정확으로 인한 잘못된 실행계획 선택
  • N+1 쿼리, 대용량 JOIN

트랜잭션/잠금 레이어:

  • 긴 트랜잭션이 잠금을 오래 점유
  • 데드락 빈발
  • SELECT ... FOR UPDATE 남용

리소스 레이어:

  • 디스크 IOPS 포화 (쓰기 피크, checkpoint, compaction 동시 발생)
  • 메모리 부족으로 인한 swap IO
  • CPU 포화 (analytics 쿼리가 OLTP와 경합)

커넥션 레이어:

  • 과도한 연결 수로 스케줄링 overhead
  • connection churn (연결 맺고 곧바로 끊기 반복)

SLI와 SLO 설정 가이드

지연 장애의 SLI는 p99 쿼리 응답시간이다. 평균 latency는 outlier를 숨기기 때문에 SLO 기준으로 적합하지 않다.

대상SLISLO 예시
OLTP 읽기 쿼리p99 read latency≤ 50ms
OLTP 쓰기/커밋p99 commit latency≤ 100ms
트랜잭션 에러율lock wait timeout 비율≤ 0.01%
슬로우 쿼리1초 초과 쿼리 수일별 top 20 검토 기준

p99 vs p95: p99가 더 엄격하지만 측정 샘플이 충분해야 의미 있다. 분당 100건 이하의 저트래픽 DB라면 p95가 더 안정적인 SLI다.

지연 장애 진단 흐름

p99 latency 급증 Slow query log 확인
pt-query-digest / pg_stat_statements
↓ 특정 쿼리 식별
실행계획 확인 EXPLAIN ANALYZE
Full Scan → 인덱스 추가
잘못된 Join → 통계 갱신
잠금 확인 SHOW ENGINE INNODB STATUS
pg_locks / pg_blocking_pids
긴 트랜잭션 kill
리소스 확인 iostat / vmstat
IOPS 한도 초과?
swap 사용량?
지연 장애 진단 흐름

범주 3: 데이터 손상

데이터 손상은 발생 빈도는 낮지만 가장 심각한 결과를 가져온다. 복구가 불완전하거나 손상을 뒤늦게 발견하면 실질적 데이터 손실로 이어진다.

손상의 두 유형

물리적 손상 (Physical corruption):

  • 스토리지 하드웨어 결함, 배드 섹터
  • RAID 실패, 비정상 셧다운으로 인한 partial write (torn page)
  • InnoDB: innodb_checksum_algorithm으로 페이지 체크섬 검증
  • PostgreSQL: data_checksums 활성화 시 block-level 체크섬 감지

논리적 손상 (Logical corruption):

  • 버그 있는 배포로 인한 잘못된 데이터 기록
  • 실수로 실행한 DROP TABLE, DELETE WITHOUT WHERE
  • 외래키 제약 없이 관계를 깨는 배치 작업
  • 충돌 없이 실행됐으나 비즈니스 규칙을 위반한 데이터

물리적 손상은 DB 엔진이 감지하지만, 논리적 손상은 애플리케이션 레이어 또는 사람이 발견하기 전까지 모른다.

SLI와 SLO

데이터 손상은 연속 지표가 아니다. 이벤트 카운트로 관리한다.

SLI: 물리적 체크섬 실패 이벤트 수 / 월
SLO: 0건 (감지 즉시 P0 알림)

SLI: 복구 불가능한 데이터 손실 바이트 수
SLO: 0 bytes (RTO/RPO에서 파생)

물리적 손상 감지 후 대응 순서:

  1. 해당 인스턴스를 즉시 읽기 전용으로 전환하여 손상 확산 방지
  2. 복제본에 동일 문제가 전파됐는지 확인
  3. 마지막 정상 백업 시점 식별
  4. PITR 또는 백업 복구로 최소 손실 복구 시도
  5. 복구 후 checksum/row count/애플리케이션 smoke test 수행

예방 체크리스트

  • [ ] InnoDB innodb_checksum_algorithm = crc32 (MySQL 기본값 확인)
  • [ ] PostgreSQL initdb --data-checksums 또는 pg_checksums 활성화
  • [ ] 중요 테이블에 대한 DROP / TRUNCATE DDL에 명시적 승인 프로세스
  • [ ] 대량 DML 전 pt-table-checksum 또는 row count 사전 스냅샷
  • [ ] 주 1회 이상 backup restore 검증 (전체 혹은 샘플)

범주 4: 복제 지연

복제 지연은 replica(secondary)가 primary의 변경 사항을 따라잡지 못하는 상태다. 읽기를 replica에서 분산하는 구조에서는 사용자에게 과거 데이터를 보여주는 현상으로 나타난다. 장바구니에 담은 상품이 안 보이거나, 결제 후 잔액이 갱신 안 된 것처럼 보이는 것이 대표적이다.

복제 지연의 주요 원인

원인MySQLPostgreSQL
단일 스레드 apply멀티스레드 복제 미설정 (slave_parallel_workers=0)max_wal_senders 부족
대형 트랜잭션수백만 row UPDATE 한 트랜잭션대형 COPY/VACUUM
쓰기 폭증DDL/배치 실행 중 복제 밀림대량 INSERT 후 replica 따라잡기
Replica 리소스 부족Primary보다 낮은 IOPS/CPU동일한 문제
Replication slot 방치WAL이 쌓여 디스크 포화slot lag 미모니터링

복제 지연 확인 명령

-- MySQL: replica에서 실행
SHOW REPLICA STATUS\G
-- Seconds_Behind_Source: 현재 지연(초)

-- PostgreSQL: primary에서 실행
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn,
       (sent_lsn - replay_lsn) AS replication_lag_bytes
FROM pg_stat_replication;

-- PostgreSQL: replica에서 실행
SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;

Split-brain: 복제 장애의 최악 시나리오

Split-brain은 primary 장애 시 자동 failover가 잘못 실행되어 두 노드가 동시에 쓰기를 받는 상태다. 두 primary에 기록된 데이터는 서로 충돌하며, 이후 합치는 과정에서 일부 데이터는 항상 손실된다.

Split-brain 발생 조건:

  • 네트워크 분리로 primary가 살아있지만 replica에서 보이지 않을 때
  • 자동 failover가 quorum 없이 동작할 때
  • STONITH(Shoot the Other Node in the Head) 없이 HA 구성할 때

방지 수단:

  • quorum 기반 failover (예: Orchestrator, Patroni, MHA)
  • fencing 메커니즘: old primary를 강제 격리하거나 STONITH 설정
  • failover 전 최소 N개 replica가 동의해야 승격 허용
  • semi-synchronous replication으로 primary가 최소 1개 replica에 commit 확인 후 진행

복제 지연 SLO

SLI: replica lag (초) — pg_stat_replication 또는 Seconds_Behind_Source
SLO: 99%의 시간 동안 30초 이하 유지 (서비스 특성에 따라 조정)

경보 1단계: 30초 초과 → 원인 파악 시작
경보 2단계: 5분 초과 → 해당 replica로의 읽기 분산 중단 고려
경보 3단계: 30분 초과 → replica 상태 이상 가능성, P1 대응

SLO 설계의 실용적 원칙

DB SLO를 처음 만들 때 흔히 하는 실수는 "DB 가용성 99.99%"처럼 단 하나의 지표로 전부를 설명하려는 것이다. DB 장애는 범주가 다양하기 때문에, 범주별로 별도의 SLI와 SLO를 정의해야 의미 있는 운영이 가능하다.

DB SLO 정의 템플릿

범주SLI 이름측정 방식SLO 값Error Budget
접속 가용성connection_success_rate성공 연결 / 전체 시도≥ 99.9%분/월 43.8분
쓰기 지연p99_commit_latency_msp99 커밋 응답시간≤ 100ms시간의 1% 허용
읽기 지연p99_read_latency_msp99 읽기 응답시간≤ 50ms시간의 1% 허용
복제 신선도replica_lag_secondsreplica lag (초)≤ 30초 99%-
데이터 무결성corruption_eventschecksum 실패 건수0건/월허용 없음

Error Budget 활용

SLO를 정의하면 자동으로 error budget이 생긴다. 예를 들어 p99 커밋 지연 SLO가 99%이면, 월 44분의 허용 예산이 생긴다. 이 예산이 소진되면:

  • 기능 배포를 중단하고 안정화 작업을 우선시한다.
  • 배포 전 load test, replay test를 의무화한다.
  • 인덱스 추가, 파라미터 변경처럼 리스크 있는 작업을 뒤로 미룬다.

error budget은 DBA 혼자 관리하는 지표가 아니라, 개발팀·운영팀·비즈니스와 공유하는 협상 기준이다.


장애 수신 시 첫 60초 체크리스트

1. 애플리케이션 에러 타입 확인
   - Connection refused / timeout → 접속 장애 범주
   - Slow response, lock wait → 지연 장애 범주
   - Data mismatch, checksum → 손상 범주
   - Stale read, replica diverged → 복제 지연 범주

2. primary가 쓰기를 받고 있는가?
   → 못 받고 있다면: failover 상태, LB 전환 여부 확인

3. connection 사용률 확인
   → 80% 이상: pool/max_connections 증설 또는 긴 트랜잭션 종료

4. 최근 30분 이내 변경사항 있었는가?
   → 배포, DDL, 파라미터 변경, 배치 실행, 트래픽 급증

5. 완화 조치가 부작용을 만드는가?
   → 예: long transaction kill은 일부 작업 롤백 발생
   → 예: replica 승격은 기존 replica 재동기화 필요

기억할 문장

"DB가 이상하다"는 말은 진단의 시작이 아니라 끝이다. 어느 범주의 장애인지를 30초 안에 구분할 수 있을 때, 비로소 의미 있는 완화와 회복이 시작된다. 범주 없이 SLO를 만들면 숫자는 있어도 행동이 나오지 않는다.

다음 장에서는 내구성을 보장하는 백업 전략 — full, incremental, logical, physical, snapshot — 과 보존 정책을 다룬다.

References

  • Google SRE Book, Chapter 4: Service Level Objectives — https://sre.google/sre-book/service-level-objectives/
  • Google SRE Workbook, Chapter 2: Implementing SLOs — https://sre.google/workbook/implementing-slos/
  • Google SRE Workbook, Error Budget Policy — https://sre.google/workbook/error-budget-policy/
  • Percona Blog, It's All About Replication Lag in PostgreSQL — https://www.percona.com/blog/its-all-about-replication-lag-in-postgresql/
  • MySQL 8.4 Reference: Replication Lag — https://dev.mysql.com/doc/refman/8.4/en/replication-administration-status.html
  • PostgreSQL Documentation: pg_stat_replication — https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-REPLICATION-VIEW
  • Datadog Guide: Alert on anomalous p99 latency of a database service — https://docs.datadoghq.com/tracing/guide/alert_anomalies_p99_database/