Skip to content

10a-3. 프로덕션 진단과 장애 대응 ​

한 줄 요약: 이 문서를 읽고 나면 원인을 모르는 프로덕션 신호에서 출발해 계층을 좁히는 진단 절차를 실행하고, 원인 규명보다 완화를 먼저 수행한 뒤 탐지 실패까지 포함한 재발 방지 조치를 남길 수 있다.

이 문서는 10a-1의 신호 설계와 10a-2의 릴리스 식별·SLI를 전제로 한다. 장애 대응 절차와 회고 원칙은 Google SRE Book/Workbook의 사고 관리 모델을 참조하되, 팀 규모에 맞게 축소하는 방법을 함께 다룬다. 성능 개선 루프 자체는 8-3에서 세운 것을 회귀 진단 방향으로 뒤집어 사용한다.

학습 목표 ​

  • 프로덕션 신호에서 시간·릴리스·대상·계층·변경의 축으로 가설 공간을 좁히는 진단 절차를 실행할 수 있다.
  • 클라이언트 지표와 서버 지표의 불일치를 근거로 문제가 어느 계층에 있는지 판별할 수 있다.
  • 원인 규명 전에 사용자 영향을 줄이는 완화 수단을 비용·되돌림 범위 기준으로 선택할 수 있다.
  • 장애 타임라인을 구간별로 나눠 기록하고, 탐지 지연을 별도의 조치 대상으로 식별할 수 있다.
  • 비난 없는 회고에서 기여 요인을 계층적으로 분석하고, 소유자와 기한이 있는 재발 방지 조치를 설계할 수 있다.

배경: 왜 이것이 존재하는가 ​

알림이 울렸다. "결제 플로우 성공률이 에러 버짓을 14배 속도로 소진 중." 이 시점에 있는 정보는 그게 전부다. 어떤 코드가 문제인지, 우리 배포 때문인지, 애초에 우리 문제인지 모른다.

이 상황에서 흔한 실패는 코드부터 읽는 것이다. 최근 PR을 열어 보고, 의심스러운 함수를 들여다보고, 로컬에서 재현을 시도한다. 재현되지 않는다. 30분이 지나고 사용자는 계속 결제에 실패하고 있다.

진단이 코드 읽기로 시작하면 안 되는 이유는 두 가지다. 첫째, 가설 공간이 너무 넓다. 우리 코드, 우리 배포, API, CDN, 서드파티, 브라우저, 사용자 환경 중 어디든 원인일 수 있다. 코드 읽기는 이 중 하나의 가지만 탐색한다. 둘째, 프론트엔드에서는 원인 코드가 우리 저장소에 없는 경우가 흔하다. 브라우저가 업데이트됐거나, 서드파티 스크립트가 새 버전을 배포했거나, CDN 설정이 바뀌었거나, API가 응답 형식을 바꿨을 수 있다.

효율적인 진단은 신호의 차원으로 가설 공간을 반씩 잘라 나가는 이분 탐색에 가깝다. 각 단계에서 던지는 질문은 "이 코드가 맞나?"가 아니라 **"이 차원으로 나눴을 때 문제가 한쪽에 격리되는가?"**다.

그리고 진단과 대응은 별개의 트랙으로 동시에 진행된다. 원인을 완전히 알아야 조치할 수 있다는 생각이 장애를 길게 만든다. 원인을 몰라도 영향을 줄일 수 있다면 그것을 먼저 한다.

핵심 개념 ​

진단은 다섯 개의 축으로 가설을 자른다 ​

신호가 들어오면 코드를 읽기 전에 다음 축으로 데이터를 잘라 본다. 각 축은 "문제가 여기 한쪽에만 있는가"를 묻는다.

축질문격리되면 알 수 있는 것
시간정확히 언제부터인가?그 시각에 일어난 변경(배포, 설정, 외부 사건)이 용의자다
릴리스특정 릴리스에서만인가?우리 배포가 원인. 롤백이 유효한 완화 수단이 된다
대상특정 route·브라우저·기기·지역·플래그 분기인가?조건부 코드 경로나 환경 의존성
계층클라이언트 / 자산·CDN / API / 서드파티 / 사용자 환경 중 어디인가?조치 주체와 수단이 정해진다
변경우리가 아닌 무엇이 바뀌었는가?우리 코드가 그대로여도 깨질 수 있다

순서에도 이유가 있다. 시간과 릴리스가 가장 저렴하고 판별력이 높다. 신호 그래프에서 상승이 시작된 시각을 찾고, 그 시각을 배포 이력과 대조하는 데는 몇 분이면 된다. 여기서 격리되면 남은 탐색 공간이 한 배포의 diff로 줄어든다.

text
신호 그래프에서 상승 시작 시각을 읽는다      14:07
배포 이력과 대조                             14:05 릴리스 a7f3e2 배포
릴리스 차원으로 오류율 분해
  릴리스 a7f3e2  4.2%   ← 격리됨
  릴리스 9c1d80  0.3%
→ 탐색 공간이 a7f3e2의 diff로 축소된다

격리되지 않는 경우가 오히려 정보다. 모든 릴리스에서 동일하게 발생한다면 우리 배포가 원인이 아니다. 이때 다음 축인 "변경"으로 넘어간다.

"우리가 아닌 무엇이 바뀌었는가" ​

프론트엔드 장애 진단에서 서버 경험이 가장 잘 배신하는 지점이다. 서버는 우리가 배포하지 않으면 대체로 그대로지만, 브라우저 애플리케이션은 우리가 아무것도 하지 않아도 실행 환경이 바뀐다.

외부 변경전형적 증상확인 방법
브라우저 업데이트특정 브라우저 버전에서만 급증. 배포와 무관한 시점오류를 브라우저 버전 차원으로 분해. 릴리스 노트 확인
서드파티 스크립트 배포우리 코드가 아닌 도메인의 스택 프레임. LoAF의 script 귀속스크립트 도메인별 오류·차단 시간 추이
CDN·인프라 설정 변경자산 404, CORS 헤더 소실, 캐시 정책 변화엣지 로그, 자산 응답 헤더 직접 확인
API 응답 변화파싱 오류, 특정 필드 undefined 접근실패 응답 본문 샘플, API 배포 이력 대조
확장 프로그램 업데이트chrome-extension:// 프레임이 급증확장 프레임 버킷의 추이
인증서·도메인 만료특정 시각에 전면 실패인증서 유효기간, DNS 변경 이력

여기서 자산 응답 헤더를 직접 확인하는 습관이 중요하다. 대시보드는 우리가 수집하도록 설계한 것만 보여 준다. CDN이 CORS 헤더를 빠뜨리기 시작한 사건은 대시보드에 "오류 증가"로만 나타나고, 원인은 curl -I로 자산을 직접 찍어 봐야 보인다.

bash
# 배포 자산이 실제로 무엇을 반환하는지 확인한다
curl -sI https://cdn.example.com/assets/main.a3f9.js | grep -iE 'access-control|cache-control|content-type|^HTTP'

계층을 판별하는 증거 ​

"클라이언트 문제인가 서버 문제인가"는 논쟁이 아니라 데이터로 답할 수 있다. 각 계층은 서로 다른 신호 조합을 만든다.

계층판별 증거반증
클라이언트 코드특정 릴리스에 격리. 스택이 우리 번들. 서버 지표 정상모든 릴리스에서 발생하면 아니다
자산·CDN자산 404/5xx, ChunkLoadError 급증, 엣지 로그의 오류율자산 응답이 모두 200이면 아니다
API·백엔드클라이언트와 서버 모두 실패율 상승. 상태 코드가 5xx서버 지표가 정상인데 클라이언트만 실패하면 아니다
네트워크·경계클라이언트 실패율 ≫ 서버 5xx 비율. Failed to fetch, CORS, 타임아웃두 지표가 같이 움직이면 아니다
서드파티스택·LoAF가 외부 도메인을 가리킴. 해당 스크립트 차단 시 재현 안 됨스크립트를 막아도 재현되면 아니다
사용자 환경특정 확장·브라우저·지역에만. 전체 비율은 낮음전 구간에서 균등하면 아니다

가장 유용한 한 줄은 클라이언트 실패율과 서버 5xx 비율의 비교다(10a-2). 두 값이 함께 오르면 백엔드, 클라이언트만 오르면 그 사이의 무언가 — 네트워크, CORS, 프록시, 타임아웃, 또는 응답을 처리하는 우리 코드다. 이 한 번의 비교로 조치 주체가 갈리므로, 장애 대시보드에는 이 두 값을 나란히 두는 것이 좋다.

성능 회귀는 개선 루프를 뒤집어 진단한다 ​

8-3의 개선 루프는 "field에서 문제 확인 → lab에서 재현 → 병목 찾기 → 조치 → 재측정"이다. 회귀 진단은 방향이 반대다. 좋았던 상태가 있으므로 비교 대상이 있다.

text
1. 언제부터 나빠졌는가            → 릴리스·시각 격리
2. 어느 route·기기에서 나빠졌는가  → 차원 분해 (전체 p75는 회귀를 숨긴다)
3. 지표의 어느 구간이 늘었는가     → attribution / subpart 분해
4. 그 구간에 해당하는 변경은?      → 배포 diff, 자산 크기, API 응답 시간
5. lab에서 두 릴리스를 같은 조건으로 비교

3단계의 subpart 분해가 조치 계층을 결정한다.

늘어난 구간의심 대상확인 방법
LCP의 TTFB서버·CDN·SSR 렌더 시간Server-Timing, 서버 응답 시간 분포, 캐시 적중률
LCP의 resource load delay리소스 발견 지연, priority 변경HTML 구조 변경 여부, preload 제거, LCP 요소 변경
LCP의 render delayrender-blocking 자산, hydration, long task배포 간 번들 크기 비교, LoAF의 script 귀속
INP의 input delay메인 스레드 점유 증가새로 추가된 스크립트, 서드파티, 폴링 로직
INP의 processing핸들러 내부 작업 증가해당 상호작용을 다루는 컴포넌트의 diff
CLS공간 예약이 빠진 새 요소신규 배너·광고·이미지, 폰트 변경

4단계에서 가장 자주 답을 주는 것은 배포 간 자산 크기 비교다. CI에 번들 크기를 기록해 두면, "왜 갑자기 느려졌는가"의 상당수가 "의존성 하나가 300KB를 들고 들어왔다"로 끝난다.

bash
# 릴리스 간 자산 크기 비교 (개념 예시)
git checkout 9c1d80 && pnpm build && du -sb dist/assets/*.js | sort -rn > /tmp/before.txt
git checkout a7f3e2 && pnpm build && du -sb dist/assets/*.js | sort -rn > /tmp/after.txt
diff /tmp/before.txt /tmp/after.txt

대응 흐름: 완화가 원인 규명보다 먼저다 ​

사고 대응은 네 구간으로 나뉜다.

text
탐지(detect)  →  분류(triage)  →  완화(mitigate)  →  복구·정리(resolve)
                     │                  │
                     │                  └─ 원인을 몰라도 실행할 수 있다
                     └─ 심각도 판정, 대응 체계 가동, 커뮤니케이션 시작

분류의 핵심은 심각도(severity) 판정이며, 기준은 기술적 이상함이 아니라 사용자 영향이다.

심각도기준 (예시)대응
SEV1핵심 플로우가 다수 사용자에게 불가능. 데이터 손상·유출즉시 대응, 완화 최우선, 상태 공지
SEV2핵심 플로우 일부 실패 또는 특정 세그먼트 전면 실패즉시 대응, 업무 시간 외 호출 대상
SEV3우회 가능한 기능 저하, 소수 영향다음 업무일 처리

이 표는 팀마다 다르게 정의해도 되지만 미리 정의해 두는 것이 중요하다. 장애 중에 "이게 심각한가"를 논의하는 시간이 대응 시간에서 그대로 빠져나간다.

완화는 원인 규명과 병렬로 진행한다. 이 원칙이 실무에서 가장 자주 무시된다. "원인을 알아야 제대로 고칠 수 있다"는 맞지만, 사용자는 우리가 원인을 이해하는 동안 계속 실패하고 있다. 완화를 먼저 하고 원인은 이후에 분석한다.

예외는 있다. 완화 자체가 상황을 악화시킬 수 있을 때다. 데이터 마이그레이션이 포함된 배포의 롤백, 이미 잘못된 데이터를 쓰기 시작한 상태에서의 되돌림은 원인 이해 없이 실행하면 더 큰 사고가 된다. 이 경우에도 "트래픽을 이전 버전으로 돌린다" 대신 "해당 기능만 끈다" 같은 더 좁은 완화를 찾는다.

역할은 팀 규모에 맞게 축소한다. 대규모 조직은 지휘(incident commander)·소통(communications)·실행(operations)을 나누지만, 1~3인 프로젝트에서는 한 사람이 겸한다. 이때도 최소한 지키는 것은 두 가지다. ① 조치를 하는 사람과 기록을 남기는 사람이 같더라도, 기록은 실시간으로 남긴다(사후에 복원하려면 정확한 시각이 사라진다). ② 조치는 한 번에 하나씩 한다(동시에 세 가지를 바꾸면 무엇이 효과가 있었는지 알 수 없다).

완화 수단은 준비 비용과 되돌림 범위로 비교한다 ​

수단소요 시간사전 준비되돌리는 범위제약
이전 릴리스로 롤백분 단위이전 자산 보존, 원클릭 배포그 배포의 전부스키마·데이터 마이그레이션이 얽히면 불가
기능 플래그 끄기초~분플래그 인프라, 코드에 분기그 기능만플래그가 없으면 쓸 수 없다
서드파티 스크립트 제거분 단위설정으로 제어 가능한 구조해당 스크립트태그 매니저를 거치면 지연될 수 있다
CDN 캐시 무효화·이전 자산 서빙분~십분이전 빌드 자산 보존자산 계층전역 전파에 시간이 걸린다
트래픽 일부 차단·우회분 단위엣지 규칙 편집 권한해당 경로정상 사용자도 막을 수 있다
hotfix 배포십분~시간CI 파이프라인특정 결함가장 느리고 새 결함 위험

표의 요점은 완화 속도가 사전 준비에 거의 전적으로 의존한다는 것이다. 롤백은 이전 릴리스의 자산이 남아 있고 배포 파이프라인이 되돌리기를 지원할 때만 분 단위다. 기능 플래그는 코드에 분기가 미리 들어 있을 때만 초 단위다.

그래서 장애 대응 준비의 절반은 되돌릴 수 있는 배포를 설계하는 것이다(10-1의 ADR 대상이기도 하다).

  • 이전 릴리스의 정적 자산을 일정 기간 유지한다. 청크 404 완화와 롤백 가능성을 동시에 얻는다.
  • 위험한 변경은 기능 플래그 뒤에 둔다. "플래그를 붙일 만큼 위험한가"의 기준을 팀에서 정한다.
  • 배포와 마이그레이션을 분리한다. 스키마 변경은 앞뒤 버전 모두와 호환되게 단계를 나눈다.
  • 롤백 절차를 실제로 한 번 실행해 본다. 문서로만 있는 절차는 장애 중에 작동하지 않는 경우가 많다.

타임라인은 구간을 나눠야 조치 대상이 보인다 ​

장애 기록에서 "14:07 발생, 15:30 복구"만 남기면 배울 것이 거의 없다. 시각을 구간으로 나눠야 어디가 느렸는지 드러난다.

시각의미이 구간이 길면
T0 발생결함이 사용자에게 영향을 주기 시작한 시각—
T1 최초 신호텔레메트리에 이상이 나타난 시각신호 자체가 없다 → 계측 공백
T2 탐지알림이 울리거나 사람이 인지한 시각알림 임계·창 설정 문제 → 탐지 설계
T3 대응 시작사람이 실제로 조사를 시작한 시각호출 경로·알림 피로 → 운영 체계
T4 완화사용자 영향이 멈춘 시각진단이 느렸거나 완화 수단이 없었다 → 완화 준비
T5 복구정상 상태로 완전히 돌아온 시각—
text
예시 타임라인

14:07  T0  결제 API 응답 형식 변경으로 클라이언트 파싱 실패 시작
14:09  T1  클라이언트 결제 실패율 상승 (신호는 있었다)
14:51  T2  고객 문의 3건 접수 후 인지 (알림은 울리지 않았다)   ← 42분
14:58  T3  조사 시작
15:12  T4  이전 API 버전으로 롤백, 실패 중단
15:40  T5  클라이언트 방어 코드 배포 후 정상화

가장 긴 구간: T1 → T2 = 42분
조치 대상은 "파싱 코드"가 아니라 "결제 실패율에 알림이 없었다"는 사실이다.

이 분해가 회고의 질을 결정한다. 원인 코드만 고치면 다음 장애도 42분 늦게 발견된다. 탐지 지연이 진단 시간보다 길다면, 그 장애의 가장 중요한 교훈은 코드가 아니라 관측 설계에 있다.

비난 없는 회고는 관대함이 아니라 진단 기법이다 ​

"개발자가 테스트를 안 했다"를 원인으로 적으면 회고가 거기서 끝난다. 다음 조치는 "더 주의하기"가 되고, 시스템은 아무것도 배우지 못한다. 비난 없는(blameless) 회고는 사람에게 관대하기 위한 예의가 아니라, 원인 분석을 사람에서 멈추지 않게 하는 방법론이다.

같은 사건을 시스템 관점으로 옮기면 질문이 이어진다.

text
"테스트를 안 했다"
  → 왜 테스트 없이 머지됐는가?          CI에 해당 검증이 없다
  → 왜 리뷰에서 걸리지 않았는가?         변경의 위험 신호가 PR에 드러나지 않았다
  → 왜 배포 후 즉시 드러나지 않았는가?   해당 플로우에 알림이 없다
  → 왜 42분 동안 아무도 몰랐는가?        고객 문의가 유일한 탐지 경로였다

각 질문이 서로 다른 조치를 만든다. 재발 방지 조치는 계층을 나눠 최소 한 개씩 배치하는 것이 좋다.

조치 계층목적예시
유입 차단같은 결함이 다시 들어오지 못하게회귀 테스트, 계약 테스트, 타입 경계 강화
탐지 개선다음에는 더 빨리 알도록해당 플로우 SLI와 알림 추가, 대시보드에 지표 배치
완화 수단다음에는 더 빨리 멈출 수 있도록기능 플래그 도입, 롤백 절차 자동화
결함 제거근본 원인 자체를 없애기코드 수정, 계약 명시, 의존성 교체

네 계층 중 탐지 개선이 가장 자주 빠진다. 원인을 고치고 나면 안심되기 때문이다. 하지만 다음 장애는 다른 원인으로 온다. 탐지 능력만이 원인과 무관하게 재사용된다.

각 조치에는 소유자와 기한을 붙인다. 이것이 없는 조치 목록은 대체로 실행되지 않는다. 조치 개수도 제한하는 편이 낫다. 12개의 조치를 적고 2개를 실행하는 것보다, 4개를 적고 4개를 실행하는 편이 시스템을 실제로 바꾼다.

실무 관점 ​

재현되지 않는 오류를 언제 닫을 것인가 ​

프로덕션 오류의 상당수는 로컬에서 재현되지 않는다. 무한정 붙들고 있을 수는 없으므로 판단 기준이 필요하다.

  • 영향도가 낮고 감소 추세 — 닫되, 재발 시 다시 열리도록 규칙을 둔다.
  • 영향도는 낮지만 증가 추세 — 닫지 않는다. 증가 추세는 원인이 살아 있다는 신호다.
  • 재현이 안 되는데 영향이 큼 — 닫지 말고 관측을 추가한다. 해당 코드 경로에 컨텍스트(입력 형태, 상태 스냅샷, 이전 사용자 행동)를 붙여 배포하고, 다음 발생을 기다린다. 이것이 재현 시도보다 빠른 경우가 많다.
  • 우리가 고칠 수 없음(확장·봇·사용자 환경) — 별도 버킷으로 옮기고 추이만 본다(10a-2).

알림 피로는 탐지 능력을 실제로 파괴한다 ​

알림이 하루에 40번 울리면 사람은 알림을 보지 않게 된다. 이것은 개인의 태만이 아니라 예측 가능한 결과다. 그리고 이 상태에서는 진짜 장애도 놓친다.

  • 알림 개수가 아니라 행동 가능성으로 판단한다. 받았을 때 할 일이 없는 알림은 알림이 아니라 대시보드 항목이다.
  • 알림마다 "받으면 처음 열어 볼 대시보드"와 "확인할 것"을 붙여 둔다. 이것을 쓸 수 없는 알림은 대개 삭제 대상이다.
  • 오탐이 반복되면 임계를 조정하거나 최소 표본 수 조건을 추가한다. 무시하기 시작하는 것이 최악이다.
  • 정기적으로 알림 발화 이력을 검토한다. 지난달 발화한 알림 중 실제 조치로 이어진 비율이 낮으면 알림 설계가 잘못된 것이다.

1~3인 프로젝트로 축소하기 ​

on-call 로테이션도, 상태 페이지도 없는 규모에서도 대부분의 요소는 축소해서 적용할 수 있다.

대규모 조직소규모 대응
심각도 등급 체계"지금 깨우는가 / 내일 보는가" 두 단계면 충분하다
incident commander 분리한 사람이 겸하되, 조치는 한 번에 하나씩
실시간 상황 채널메모 파일에 시각과 함께 조치를 적어 나간다
공식 상태 페이지영향받은 사용자에게 알릴 최소 경로 하나
포스트모템 문서 템플릿타임라인 + 기여 요인 + 조치 4계층, 한 페이지

축소해도 포기하지 말아야 할 것은 실시간 기록과 탐지 지연의 별도 분석이다. 이 둘이 규모와 무관하게 학습을 만든다.

안티패턴 ​

  • 코드부터 읽기 — 가설 공간을 좁히기 전에 특정 가지만 탐색한다. 시간·릴리스 축을 먼저 자른다.
  • 원인 규명 후 완화 — 사용자 영향이 진단 시간만큼 길어진다. 두 트랙을 병렬로 돌린다.
  • 동시에 여러 조치 적용 — 무엇이 효과가 있었는지 알 수 없어 다음 장애에 재사용할 지식이 남지 않는다.
  • 타임라인을 "발생~복구"로만 기록 — 탐지 지연이 보이지 않아 관측 개선이 조치 목록에 오르지 못한다.
  • 회고 조치에 소유자·기한 없음 — 목록만 쌓이고 실행되지 않는다. 다음 회고에서 같은 조치가 다시 적힌다.
  • 원인 수정만으로 회고 종료 — 다음 장애는 다른 원인으로 오고, 탐지는 여전히 느리다.
  • 롤백 절차를 문서로만 보유 — 실제로 실행해 본 적 없는 절차는 장애 중에 작동하지 않는 경우가 많다.

더 깊이 ​

릴리스가 여러 개 겹쳤을 때의 이분 탐색

릴리스 축으로 격리했는데 그 릴리스에 커밋 40개가 들어 있다면, 7-8의 git bisect를 그대로 쓸 수 있다. 다만 프론트엔드에서는 판정 함수를 만드는 것이 어렵다. "이 커밋에서 문제가 있는가"를 자동으로 판정하려면 재현 가능한 조건이 필요한데, 프로덕션에서만 나타나는 문제는 그 조건 자체가 없다.

대안은 두 가지다. ① 문제와 관련된 축(번들 크기, 특정 자산 존재 여부, 렌더 결과의 DOM 구조)으로 판정 함수를 근사한다. ② 커밋이 아니라 의존성 변경과 설정 변경만 먼저 본다. 프로덕션에서만 나타나는 문제는 애플리케이션 코드보다 빌드 설정·의존성·환경 변수에서 오는 비율이 높다.

사용자 영향은 항상 하한선으로 보고한다

장애 리포트의 "영향받은 사용자 약 3,200명"은 어떻게 계산했는지 함께 적어야 한다. 클라이언트 텔레메트리 기반 추정은 10a-1에서 본 이유로 언제나 과소 추정이다. 표본율이 10%였다면 그만큼 되곱해야 하고, 완전히 실패한 세션은 애초에 세어지지 않는다.

text
영향 추정 (하한선)
  텔레메트리 기준 영향 세션      412
  표본율 보정 (10% 수집)      × 10  → 약 4,120 세션
  고유 사용자 추정                    약 3,200명
  포함되지 않음: 부팅 실패로 보고되지 않은 세션, 수집 차단 사용자
  교차 확인: CDN 로그의 결제 페이지 요청 수 대비 성공 콜백 비율 → 유사 규모

교차 확인 없이 단일 출처로 영향도를 보고하면, 그 숫자가 이후 우선순위 결정의 근거로 계속 재사용된다.

정리 ​

  • 진단은 코드 읽기가 아니라 시간·릴리스·대상·계층·변경 축으로 가설 공간을 좁히는 절차다. 시간과 릴리스가 가장 저렴하고 판별력이 높다.
  • 프론트엔드는 우리가 배포하지 않아도 실행 환경이 바뀐다. "우리가 아닌 무엇이 바뀌었는가"가 1순위 질문이 되는 경우가 많다.
  • 클라이언트 실패율과 서버 5xx 비율의 비교 한 번으로 조치 주체가 갈린다.
  • 성능 회귀는 개선 루프를 뒤집어 진단한다. subpart·attribution 분해가 조치 계층을 결정하고, 배포 간 자산 크기 비교가 자주 답을 준다.
  • 완화는 원인 규명과 병렬로, 그리고 대개 먼저 실행한다. 완화 속도는 사전 준비(자산 보존, 기능 플래그, 롤백 자동화)에 거의 전적으로 의존한다.
  • 타임라인은 발생·최초 신호·탐지·대응·완화·복구로 나눠 기록한다. 가장 긴 구간이 조치 대상을 알려 준다.
  • 비난 없는 회고는 예의가 아니라 원인 분석을 사람에서 멈추지 않게 하는 기법이다. 조치는 유입 차단·탐지 개선·완화 수단·결함 제거의 네 계층으로 배치하고 소유자와 기한을 붙인다.

확인 문제 ​

  1. 결제 실패율이 급증했다. 클라이언트 관점 결제 API 실패율은 8%인데, 백엔드 팀은 자기 지표상 5xx 비율이 0.02%로 정상이라고 답했다. 어떻게 진행하는가?
정답과 해설

두 지표가 어긋난다는 사실 자체가 계층 정보다. 실패한 요청 대부분이 애플리케이션 서버에 도달하지 못했거나 응답이 클라이언트에 닿지 못했다는 뜻이므로, 그 사이 계층을 본다.

확인 순서: ① 클라이언트 오류의 종류를 분해한다 — Failed to fetch(네트워크·CORS), 타임아웃, 특정 HTTP 상태, AbortError(집계에서 제외해야 함). ② CDN·로드밸런서·게이트웨이 등 엣지 로그를 확인한다. 애플리케이션 서버 앞단에서 반환된 5xx나 차단은 백엔드 지표에 없다. ③ cross-origin API라면 preflight OPTIONS의 성공률을 본다. CORS 헤더 변경이 원인이면 여기서 드러난다. ④ 차원 분해로 특정 지역·네트워크·브라우저에 몰려 있는지 본다.

동시에 완화를 병렬로 준비한다. 최근 배포가 있었다면 클라이언트·API 양쪽의 롤백 가능성을 확인한다. 그리고 이 사건은 "클라이언트 관점 API 성공률"이 SLI로서 필요한 이유의 실례이므로, 회고에서 그 지표의 상시 대시보드 배치를 조치로 남긴다.

  1. 다음 타임라인에서 회고의 최우선 조치는 무엇인가?
text
09:12  결함이 사용자에게 영향 시작
09:14  텔레메트리에 오류율 상승 나타남
09:16  알림 발화
10:35  담당자가 알림을 인지하고 조사 시작
10:41  원인 특정
10:44  롤백 완료
정답과 해설

가장 긴 구간은 알림 발화(09:16) → 대응 시작(10:35)의 79분이다. 탐지 자체는 4분 만에 됐고, 진단과 완화는 9분으로 빨랐다. 즉 계측과 알림 설계는 잘 작동했다.

문제는 알림이 사람에게 도달하지 못한 것이다. 조치 대상은 코드도 관측 설계도 아니고 호출 경로와 알림 운영이다. 후보: 알림 채널이 소음에 묻혀 있는지(알림 피로), 심각도별로 채널이 분리되어 있는지, 업무 시간 외 호출 경로가 있는지, 알림 확인 책임이 특정인에게 지정되어 있는지.

여기서 흔한 실수는 원인 코드만 고치고 끝내는 것이다. 그렇게 하면 다음 장애도 79분 뒤에 대응이 시작된다. 알림 발화 이력을 검토해 오탐 비율이 높다면, 알림 수를 줄이는 것이 역설적으로 탐지 능력을 높이는 조치가 된다.

  1. 배포한 적이 없는데 어제부터 특정 화면의 오류가 급증했다. 릴리스 축으로 격리되지 않는다. 다음에 무엇을 확인하는가?
정답과 해설

우리 릴리스가 원인이 아니므로 외부 변경 축으로 넘어간다. 확인 순서는 격리 가능성이 높은 것부터다.

① 브라우저 버전 차원 분해 — 특정 브라우저의 특정 버전에만 몰려 있으면 브라우저 업데이트다. 해당 버전의 릴리스 시점과 오류 시작 시각이 일치하는지 본다. ② API 응답 변화 — 실패한 요청의 응답 본문 샘플을 확인하고, 백엔드 배포 이력을 대조한다. 필드 이름·타입 변경이 전형적이다. ③ 서드파티 스크립트 — 스택 프레임과 LoAF의 script 귀속이 외부 도메인을 가리키는지 본다. ④ CDN·인프라 설정 — 자산 응답 헤더를 직접 확인한다(CORS, 캐시, content-type). ⑤ 확장 프로그램 — chrome-extension:// 프레임 버킷의 추이. ⑥ 인증서·도메인 만료 — 특정 시각에 계단식으로 시작됐다면 유력하다.

기억할 점은, 우리 코드가 그대로여도 환경이 바뀌면 깨진다는 것이다. 그리고 이 사건의 회고 조치에는 대개 "외부 의존성 변화에 대한 방어(응답 스키마 검증, 서드파티 격리)"와 "브라우저 버전 차원의 상시 관측"이 포함된다.

  1. 팀이 롤백을 완화 수단으로 문서화해 뒀지만, 실제 장애에서 롤백에 47분이 걸렸다. 무엇이 문제였을 가능성이 높으며 회고 조치는 무엇인가?
정답과 해설

완화 속도는 사전 준비에 의존하는데, 문서만 있고 검증된 적이 없는 절차였을 가능성이 높다. 전형적인 원인: 이전 릴리스의 정적 자산이 이미 삭제되어 되돌릴 대상이 없었다, 롤백에 전체 CI 파이프라인 재실행이 필요했다, 배포 권한이 특정인에게만 있었다, 롤백 시 스키마나 API 계약이 어긋났다, 캐시 무효화 전파를 기다려야 했다.

조치는 완화 수단 계층에 속한다. ① 롤백 절차를 실제로 실행해 소요 시간을 측정하고, 그 시간을 문서에 적는다. ② 이전 릴리스 자산의 보존 기간을 정한다(청크 404 완화와 함께 얻는 이점이다). ③ 롤백을 재빌드 없이 즉시 실행 가능한 형태로 만든다. ④ 되돌리기 어려운 변경(마이그레이션, 계약 변경)은 기능 플래그로 별도 완화 경로를 준비한다. ⑤ 롤백 실행 권한을 대응 가능한 사람 모두에게 부여한다.

그리고 이 절차는 정기적으로 실제 실행해 봐야 한다. 검증되지 않은 완화 수단은 준비되지 않은 것과 같다.

참고 자료 ​