문서화와 인수인계 시리즈 6/9
장애가 나면 사람은 급해진다. 어디를 봐야 할지 기억나지 않고, 이전에 해결했던 문제도 다시 검색하게 된다. 로그 위치를 찾다가 시간을 쓰고, 같은 명령어를 다시 조합한다.
그래서 트러블슈팅 문서는 장애가 난 뒤 쓰면 늦다.
물론 실제 장애를 겪은 뒤 보강되는 부분은 있다. 하지만 최소한 자주 발생할 수 있는 증상과 확인 순서는 미리 정리해두는 것이 좋다.
문제 상황
운영 콘솔에서 반복적으로 나올 수 있는 문제는 대체로 정해져 있다.
- 화면이 로딩되지 않는다.
- API 호출이 CORS 오류로 실패한다.
- 데이터가 갱신되지 않는다.
- 다운로드 작업이 끝나지 않는다.
- Lambda가 timeout 된다.
- DB 연결이 실패한다.
- 배포했는데 이전 화면이 계속 보인다.
이런 문제는 원인이 하나가 아니다. 화면이 안 보인다고 해서 항상 프론트엔드 문제는 아니다. 데이터가 안 바뀐다고 해서 항상 DB 문제도 아니다.
그래서 트러블슈팅 문서는 원인 중심보다 증상 중심이어야 한다.
증상 중심으로 쓰기
장애를 보는 사람은 처음에 원인을 모른다.
따라서 문서는 이렇게 시작해야 한다.
| 증상 | 먼저 볼 곳 | 가능 원인 | 조치 |
|---|---|---|---|
| CORS 오류 | 브라우저 Console, API Gateway OPTIONS | OPTIONS 설정 누락 | Gateway CORS 설정 확인 |
| 다운로드 무한 대기 | job table, worker 로그 | worker 실패 또는 timeout | job 상태와 Lambda 로그 확인 |
| 데이터 미반영 | 동기화 로그, CDN 캐시 | sync 실패 또는 cache | 재동기화, invalidation |
| 배포 후 화면 그대로 | CloudFront | 캐시 무효화 누락 | invalidation 실행 |
| DB 연결 실패 | API 서버 로그 | 환경 변수, 보안그룹 | 연결 정보 확인 |
이 표는 완벽할 필요가 없다. 처음 대응할 방향을 주는 것이 목적이다.
CORS 문제를 문서화하는 법
CORS는 운영 콘솔에서 자주 발생하는 문제다.
특히 React SPA와 API 도메인이 다르면 브라우저는 preflight 요청을 보낸다. API Gateway에서 특정 path의 OPTIONS 설정이 빠지면 실제 API가 정상이어도 브라우저는 요청을 막는다.
트러블슈팅 문서에는 다음이 들어가야 한다.
- 브라우저 Console에서 확인할 오류 메시지
- Network 탭에서 OPTIONS 요청을 확인하는 방법
- API Gateway에서 OPTIONS method가 있는지 확인하는 방법
- MOCK Integration이 연결되어 있는지 확인하는 방법
- Lambda 응답에도 CORS 헤더가 있는지 확인하는 방법
- 수정 후 stage 배포가 필요한지
중요한 것은 "CORS 헤더를 추가한다"가 아니다. 어느 계층에서 누락되었는지 찾는 순서다.
다운로드 무한 대기를 문서화하는 법
리포트 다운로드는 사용자가 보기에는 버튼 하나지만, 내부적으로는 여러 단계가 있다.
요청 접수
-> job 생성
-> worker 실행
-> 파일 생성
-> object storage 업로드
-> job 완료 처리
-> 다운로드 URL 반환
어느 단계에서든 실패할 수 있다.
따라서 문서에는 다음 확인 순서가 필요하다.
- job이 생성되었는가
- 상태가
IN_PROGRESS에서 멈췄는가 - worker 로그에 예외가 있는가
- 파일이 storage에 업로드되었는가
- 완료 상태 갱신이 실패했는가
- 프론트엔드 polling이 계속되고 있는가
이 순서를 모르면 "다운로드가 안 된다"는 한 문장 앞에서 막힌다.
캐시 문제를 문서화하는 법
CloudFront 캐시는 성능을 높이지만 운영 중 혼란을 만든다.
배포했는데 예전 화면이 보일 수 있고, JSON 데이터가 갱신되지 않은 것처럼 보일 수 있다.
트러블슈팅 문서에는 다음을 적어야 한다.
- 어떤 경로가 길게 캐시되는가
- 어떤 경로는 짧은 TTL을 가져야 하는가
- 배포 후 invalidation을 해야 하는가
- 데이터 파일은 배포 스크립트에서 제외되는가
- 브라우저 캐시와 CDN 캐시를 어떻게 구분하는가
캐시 문제는 "새로고침 해보세요"로 끝내면 안 된다. CDN에서 오래된 응답이 오는지 확인해야 한다.
로그 위치는 반드시 적는다
트러블슈팅 문서에서 가장 실용적인 정보는 로그 위치다.
예를 들어 다음처럼 적는다.
| 계층 | 확인 위치 |
|---|---|
| 브라우저 | DevTools Console, Network |
| CDN | CloudFront access log |
| API Gateway | access log, stage execution log |
| Lambda | CloudWatch Logs |
| Node API | server log 또는 container log |
| DB | slow query log, connection metric |
로그 위치가 문서에 없으면 장애 때 콘솔을 뒤지게 된다. 특히 클라우드 리소스가 많아지면 이름을 찾는 데 시간이 걸린다.
내부 문서에는 실제 로그 그룹명과 리소스명을 적어야 한다. 공개 글에서는 일반화하면 된다.
명령어보다 판단 순서가 중요하다
트러블슈팅 문서에 명령어를 넣는 것은 좋다.
하지만 명령어만 있으면 위험하다. 왜 실행하는지 모르면 잘못된 상황에서 복사해 실행할 수 있다.
예를 들어 캐시 무효화 명령어가 있다면, 앞에 판단 기준이 있어야 한다.
다음 조건이면 CloudFront invalidation을 검토한다.
- 빌드는 정상 배포되었다.
- S3에는 새 파일이 올라가 있다.
- 브라우저 Network 응답이 CloudFront cache hit로 보인다.
- 특정 사용자뿐 아니라 여러 환경에서 이전 파일이 보인다.
그다음 명령어를 둔다.
aws cloudfront create-invalidation --distribution-id DISTRIBUTION_ID --paths "/*"
명령어는 마지막 단계다. 먼저 왜 필요한지 설명해야 한다.
문서 업데이트 타이밍
트러블슈팅 문서는 한 번에 완성되지 않는다.
업데이트하기 좋은 타이밍은 다음과 같다.
- 같은 문제를 두 번째 겪었을 때
- 장애 대응 후 회고를 마쳤을 때
- 새 담당자가 같은 질문을 했을 때
- 배포 절차에서 실수가 났을 때
- 로그 위치를 찾는 데 시간이 걸렸을 때
특히 "두 번째 겪었을 때"가 중요하다. 한 번은 우연일 수 있지만, 두 번 반복되면 문서화할 가치가 있다.
공개 글로 바꿀 때
트러블슈팅 문서는 블로그 글감으로 좋다. 하지만 내부 문서를 그대로 공개하면 안 된다.
제거해야 할 것:
- 실제 API URL
- 실제 AWS 리소스 ID
- 실제 로그 그룹명
- 내부 장애 날짜
- 고객 또는 파트너 식별 정보
- 보안 설정의 상세값
남길 수 있는 것:
- 증상
- 원인 유형
- 확인 순서
- 계층별 사고 방식
- 재발 방지 원칙
예를 들어 "API Gateway 특정 리소스에 OPTIONS MOCK Integration이 없어 CORS preflight가 실패했다"는 패턴은 공개해도 좋다. 하지만 실제 API ID와 경로는 제거해야 한다.
정리
트러블슈팅 문서는 장애가 난 뒤 급하게 쓰는 메모가 아니다.
운영 시스템에서 반복될 수 있는 문제를 미리 예상하고, 증상별로 확인 순서를 적어두는 문서다.
좋은 트러블슈팅 문서는 다음을 제공한다.
- 증상에서 시작하는 진단 경로
- 계층별 로그 위치
- 가능 원인과 조치
- 명령어를 실행하기 전 판단 기준
- 재발 방지를 위한 문서 업데이트 지점
장애를 완전히 없앨 수는 없다. 하지만 같은 장애 앞에서 매번 처음부터 헤매지 않게 만들 수는 있다.
그게 트러블슈팅 문서의 역할이다.
'성장과 기술 > 시스템 설계' 카테고리의 다른 글
| 기술 용어집을 프로젝트 맥락으로 쓰는 이유 (0) | 2026.05.26 |
|---|---|
| ADR은 면접 답변이 아니라 운영 자산이다 (0) | 2026.05.25 |
| README, 아키텍처 문서, HANDOVER는 역할이 다르다 (0) | 2026.05.24 |
| HANDOVER.md에 꼭 들어가야 하는 항목들 (0) | 2026.05.23 |
| 인수인계 문서는 코드 설명서가 아니라 운영 지도다 (0) | 2026.05.22 |
글에서 정리한 생각은 GitHub의 코드와 포트폴리오로 이어지고, 일부는 FamBlend 같은 제품 실험으로 확장됩니다.