Development··5 min read

새벽 3시에 프로덕션 장애 디버깅한 썰

슬랙 알림 하나로 시작된 새벽 장애 대응. 원인은 어이없는 곳에 있었다.

슬랙 알림이 울렸다, 새벽 2시 47분

자고 있었다. 진짜 깊이 자고 있었는데 핸드폰이 미친 듯이 울렸다. 슬랙 채널에 알림이 47개 쌓여 있었고, Grafana 대시보드는 온통 빨간색이었다. API 응답 시간이 평소 120ms에서 14,300ms로 뛰어 있었다.

잠옷 차림으로 노트북을 켰다. 솔직히 이 순간이 제일 싫다. 뇌가 아직 안 깨어 있는데 로그를 읽어야 하니까.

처음엔 DB를 의심했다

당연히 DB 문제라고 생각했다. 슬로우 쿼리가 있을 거라고. PostgreSQL 로그를 뒤졌는데 슬로우 쿼리가 없었다. 커넥션 풀도 정상이었다. CPU 사용률도 12%밖에 안 됐다.

(이 시점에서 이미 30분이 지나 있었다.)

Redis도 확인했다. 메모리 사용률 정상, eviction도 없고, 연결도 잘 되고 있었다. 그럼 뭐가 문제인 건지 진짜 모르겠었다.

범인은 외부 API 타임아웃이었다

한참 뒤에야 발견했다. 결제 모듈에서 외부 PG사 API를 호출하는데, 그쪽 서버가 응답을 안 주고 있었다. 타임아웃을 30초로 설정해놨던 거다. 30초. 누가 이걸 30초로 해놨냐 했더니 그게 나였다.

문제는 이 API 호출이 동기적으로 처리되고 있었다는 거다. PG사 서버가 느려지니까 우리 서버의 워커 스레드가 전부 거기서 블로킹됐고, 다른 요청들이 줄줄이 밀린 거다.

근데 왜 하필 새벽에?

알고 보니 PG사가 새벽 2시에 서버 점검을 했다. 사전 공지가 있었는데 이메일로 왔다. 그 이메일은 퇴사한 전임자 계정으로 갔다. 아무도 안 읽었다.

이게 진짜 어이없는 포인트다. 기술적인 문제가 아니라 커뮤니케이션 문제였다.

응급 처치로 한 것들

타임아웃을 30초에서 3초로 줄였다. Circuit breaker 패턴을 급하게 넣었다. 외부 API가 실패하면 결제 관련 기능만 비활성화하고 나머지 서비스는 정상 동작하도록 fallback을 추가했다.

새벽 4시 23분에 배포 완료. 서비스 정상화까지 총 1시간 36분이 걸렸다.

사후 분석에서 나온 것들

다음 날 포스트모템을 했다. 나온 액션 아이템이 7개였는데, 그중 3개가 기술적인 거고 4개가 프로세스 관련이었다. 외부 서비스 연동 담당자 이메일 갱신, 장애 대응 런북 작성, 외부 API 의존성 목록 정리.

사실 기술적으로는 타임아웃 3초로 바꾸고 서킷 브레이커 넣으면 끝이었다. 근데 그걸 6개월 동안 아무도 안 한 거다. 장애가 터지기 전까지는 아무도 신경 안 쓴다.

(나도 포함해서.)

그 뒤로 바뀐 습관

외부 API 호출하는 코드를 볼 때마다 타임아웃 설정부터 확인한다. 기본값이 뭔지, fallback이 있는지, 서킷 브레이커가 걸려 있는지. 이게 습관이 되기까지 새벽 장애 한 번이면 충분했다.

근데 솔직히 아직도 불안하다. 다음 장애는 또 어디서 터질지 모르니까. 방금 슬랙 알림 소리가 난 것 같은데 착각이겠지.

관련 글