재현 가능한 장애 기록: 판단 순서를 남기는 법
장애 메모에 명령만 복사하지 않고 관측, 가설, 분리 실험, 수정과 검증을 연결해 다음 조사에서도 재사용할 수 있게 만드는 방법.
이 글의 목차좋은 장애 기록은 정답지가 아니라 재현 가능한 지도다8
서버 CPU가 다시 100%에 가까워졌다.
재부팅하면 잠깐 나아졌지만 곧 같은 상태로 돌아왔고, top 화면에서는 계속 CPU를 차지하는 프로세스 하나가 잡히지도 않았다.
“재부팅 후 정상화”라고만 적었다면 며칠 뒤 같은 일이 생겼을 때 다시 처음부터 살펴봐야 할 상황이었다.
PM2는 Node.js 애플리케이션을 계속 실행하고, 종료되면 다시 올려 주는 프로세스 관리 도구다.
이번에는 PM2를 재시작한 명령보다 CPU가 어디에 쓰였는지, 어떤 프로세스가 새로 생겼는지, 의심한 앱을 멈췄을 때 값이 어떻게 달라졌는지를 순서대로 남겼다.
그 기록을 다시 펼치니 .npmrc의 prefix 설정과 nvm이 충돌했던 이유까지 기억에 기대지 않고 따라갈 수 있었다.
좋은 장애 기록은 정답지가 아니라 재현 가능한 지도다
장애가 끝난 직후에는 마지막에 실행한 명령이 해결책처럼 보인다.
하지만 같은 명령이 다음 장애에도 안전하다는 보장은 없다.
서버를 재부팅했더니 잠시 정상화됐다는 기록만 보고 다음 담당자가 바로 재부팅하면, 원인을 보여 주던 실행 흔적을 먼저 지울 수 있다.
다시 쓸 수 있는 기록은 다섯 종류의 문장을 구분한다.
| 구분 | 답해야 할 질문 | 이번 사례의 예 |
|---|---|---|
| 관측 | 실제로 무엇을 봤는가 | idle이 0%에 가깝고 system CPU가 높았다 |
| 가설 | 그 값으로 무엇을 의심했는가 | 짧은 프로세스 생성이 반복될 수 있다 |
| 실험 | 다른 원인과 어떻게 분리했는가 | 대상 PM2 앱만 멈췄다 |
| 수정 | 어떤 원인을 제거했는가 | npm prefix와 nvm 충돌을 정리했다 |
| 검증 | 수정 뒤 무엇이 달라졌는가 | 앱은 online, idle은 85~97%였다 |
관측과 해석을 한 문장으로 합치면 나중에 사실을 다시 검토하기 어렵다.
“PM2 때문에 CPU가 100%였다”보다 “PM2 대상 앱을 멈추자 idle이 약 96%로 바뀌었다”가 더 강한 기록이다.
앞 문장은 결론이고, 뒤 문장은 다른 사람이 다시 확인할 수 있는 증거다.
이 방식은 개발 장애에만 쓰이지 않는다.
매장 냉장고의 온도가 올랐을 때도 “냉장고가 고장 났다”보다 시간대별 온도, 문을 닫았을 때 변화, 전원과 압축기 상태를 나눠 적어야 수리 담당자가 같은 판단을 재현할 수 있다.
재부팅해도 CPU 100%가 다시 돌아왔다
처음에는 Docker, 네트워크와 디스크 입출력도 후보에 올렸다.
하지만 시스템 상태를 보여 주는 top에서 무거운 프로세스 하나가 오래 버티는 모습은 보이지 않았다.
대신 아무 작업도 하지 않은 CPU 비율인 idle이 0%에 가까웠고, 애플리케이션 계산보다 운영체제 내부 작업에 쓰이는 system CPU 비중이 높았다.
한 프로세스가 무거운 계산을 하는 문제가 아니라, 짧은 시스템 작업이 계속 반복되는 쪽을 살펴봐야 했다.
여기서 가설을 바꾼 근거는 “CPU가 높다”는 현상 자체가 아니었다.
idle이 거의 없고 system CPU가 높다는 조합이었다.
execsnoop에서 같은 실행 흐름이 계속 보였다
perf는 CPU가 어느 함수와 운영체제 경로에 머무는지 보여 주는 도구다.
여기서 clone과 execve처럼 새 프로세스를 만들고 프로그램을 실행하는 경로가 반복됐다.
아주 짧게 생겼다 사라지는 프로세스는 top에서 놓칠 수 있다.
그래서 새로 실행되는 명령을 기록하는 execsnoop을 확인했다.
PM2 아래에서 nvm use, npx serve, Node 실행이 빠르게 이어지고 있었다.
CPU를 오래 점유한 하나의 애플리케이션을 찾는 대신, PM2의 시작 흐름에서 프로세스가 계속 만들어지는 이유를 따라가야 했다.
시간축이 있어야 원인과 우연을 구분할 수 있다
로그와 지표를 모을 때는 서로 다른 화면의 시각을 같은 시간대로 맞춘다.
CPU가 오른 시각, PM2 재시작 횟수가 증가한 시각, 앱 오류가 남은 시각을 연결해야 세 현상이 같은 사건인지 판단할 수 있다.
운영 기록에는 최소한 다음 시각을 남긴다.
- 사용자 영향이 처음 확인된 시각
- 담당자가 문제를 인지한 시각
- 가설을 바꾼 관측이나 실험의 시각
- 임시 복구가 반영된 시각
- 원인 수정과 검증이 끝난 시각
서버와 대시보드의 시간대가 다르면 UTC인지 한국 시간인지도 적는다.
PID는 실행 중인 프로세스의 식별 번호이고, PPID는 그 프로세스를 시작한 부모 프로세스의 식별 번호다.
로그 한 줄을 복사할 때는 앞뒤 몇 줄과 요청 ID 또는 PID·PPID처럼 연결할 식별자를 함께 남기되, 토큰·쿠키·개인정보는 제거한다.
앱을 멈추자 CPU idle이 약 96%가 됐다
의심한 앱을 멈추자 CPU idle은 약 96%로 회복됐다.
단순히 시간이 지나 우연히 내려간 것보다, 해당 앱의 시작 흐름을 끊었을 때 수치가 달라졌다는 쪽이 더 강한 근거였다.
설정을 따라가 보니 npm의 사용자 설정 파일인 .npmrc에 전역 설치 기준 경로 prefix가 고정돼 있었다.
이 값이 Node 버전을 바꾸는 도구인 nvm의 경로 관리와 충돌하고 있었다.
prefix를 정리한 뒤 앱을 다시 올리자 PM2에서 online 상태를 유지했고, 관찰한 CPU idle은 85~97%였다.
- 처음 현상: CPU 100%에 근접, 재부팅 뒤 재발
- 판단을 바꾼 값: idle 0% 근처, 높은 system CPU
- 실행 흐름: PM2 아래에서
nvm use,npx serve, Node가 반복 - 분리 실험: 의심 앱 중지 뒤 idle 약 96%
- 원인 수정과 확인:
.npmrc의prefix정리,online유지, idle 85~97%
수정 명령 하나만 남겼다면 prefix를 왜 지웠는지 설명하기 어려웠을 것이다.
수치와 실행 흐름을 함께 남긴 덕분에 설정 충돌까지 한 줄로 이어졌다.
재부팅과 앱 중지는 해결이 아니라 복구와 실험이었다
운영 장애에서는 재부팅이나 프로세스 중지로 서비스를 먼저 살릴 수 있다.
필요한 조치지만 증상이 잠시 사라진 것과 원인이 제거된 것은 구분해야 한다.
이번 사례에서 재부팅은 임시 복구였고, 앱 중지는 원인을 좁히는 분리 실험이었다.
.npmrc의 설정 충돌을 정리한 것이 수정이고, 그 뒤 online 상태와 CPU idle 범위를 확인한 것이 검증이었다.
이 네 단계를 “재시작 후 정상”으로 합치지 않는 것이 중요했다.
같은 증상이 다른 원인으로 생기더라도 어느 단계부터 다시 확인해야 하는지 알 수 있기 때문이다.
그대로 복사해 쓸 수 있는 장애 메모 형식
아래 형식은 길게 회고를 쓰기 위한 양식이 아니다.
조사 중 판단이 바뀔 때 한 줄씩 채워 두면 장애가 끝난 뒤에도 핵심 근거가 남는다.
“정상화 확인”처럼 기준이 없는 표현은 피한다.
로그인 1회 성공, 오류 0건, CPU idle 85~97%처럼 무엇을 어느 범위에서 봤는지 적는다.
짧은 관찰 결과를 장기 재발 방지 성과처럼 확대하지 않고, 추가 모니터링이 필요하면 기간과 담당 지표를 별도로 남긴다.
다음 조사에도 쓸 수 있게 다섯 가지를 남긴다
장애 메모를 닫기 전에는 다음 질문에 답할 수 있는지 확인한다.
- 처음 증상과 실행 환경은 무엇이었나?
- 어느 관측값 때문에 기존 가설을 바꿨나?
- 원인을 좁힌 분리 실험은 무엇이었나?
- 임시 복구와 원인 수정은 각각 무엇이었나?
- 수정 뒤 어떤 값과 상태를 확인했나?
실패한 가설의 명령과 출력 전체를 복사할 필요는 없다.
무엇을 확인했고 왜 우선순위에서 내렸는지만 한 줄로 남긴다.
반대로 clone, execve처럼 검색과 판단에 쓰인 신호와 실제 수치는 텍스트로 보관한다.
서버명, 사용자 경로, 토큰과 내부 리소스 ID는 가린다.
이번 장애에서 재부팅은 CPU를 잠시 낮췄고, 앱 중지는 원인을 좁히는 실험이 됐다.
원인을 없앤 것은 .npmrc의 prefix 충돌을 정리한 일이었다.
수정 뒤에는 앱의 online 상태와 CPU idle 85~97%를 함께 확인했다.
다음 조사에서 다시 쓸 수 있었던 것은 특정 명령어보다 생각이 바뀐 근거였다.
CPU 100%라는 현상, 높은 system CPU, 반복된 프로세스 생성, 앱 중지 뒤 96%, 설정 수정 뒤 85~97%가 순서대로 이어졌기 때문이다.
그래서 장애 메모에는 “무엇을 실행했는가”만 적지 않는다.
어느 관측 때문에 다음 판단으로 넘어갔는가를 함께 남긴다.
이 기록 덕분에 다음 사람이 같은 prefix 문제를 무조건 가정할 필요도 없어졌다.
idle과 system CPU가 다르다면 다른 가설에서 시작하면 되고, 실행 계보가 같을 때만 npm과 nvm 설정을 확인하면 된다.
재현 가능한 기록의 가치는 과거 결론을 복사하게 하는 데 있지 않고, 같은 증거에서 같은 판단 지점까지 빠르게 도착하게 하는 데 있다.
이 사례의 진단 명령과 PM2 옵션은 PM2 재시작 루프로 CPU 100%가 된 원인과 해결에 따로 정리했다.