사례2건
2건 중 1~2번째
- 증상
Ballast 파일을 만드는 스크립트를 실행한 직후 에러율, 데이터베이스 연결, Health Check 알람이 수백 건 한꺼번에 울렸다. 알람 메시지를 읽기도 전에 다음 알람이 쏟아졌고, 정상적인 게임 이용이 어렵다고 본 팀은 16시 52분에 긴급 점검을 시작했다.
- 촉발
디스크가 가득 찰 때를 대비해 Ballast 파일을 만드는 스크립트를 실행했는데, 파일 경로가 잘못 설정돼 Block Device를 가리켰다. 이 명령에는 대상 경로에 파일이 이미 있는지 확인하는 안전장치가 없어 파티션을 그대로 덮어썼다.
- 원인
- 구성 요소
- 기여 요인
- 감지
작업 직후 미리 설정해 둔 메트릭으로 알았다. 에러율, 데이터베이스 연결, Health Check 알람이 수백 건 동시에 울렸다. 2차 장애는 새벽 2시 42분 데이터베이스의 모든 쿼리와 요청이 실패하는 것을 관측하고 알았다.
- 조치
- 정상적인 게임 이용이 어렵다고 보고 운영팀에 요청해 16시 52분부터 긴급 점검을 시작했다.
- SST 파일의 구조를 해독하고, 장애 다음날 오전 4시쯤 Spark로 SST 파일 내용을 CSV 텍스트 파일로 추출하는 샘플 코드를 작성했다. 예상 처리 시간이 약 24시간으로 너무 길어 CockroachDB CLI 소스코드를 필요한 작업에 맞게 고쳐 10배 이상 빠르게 했다.
- 오전 10시 30분쯤부터 마지막까지 살아남은 노드 7대의 SST 파일 약 7.5TB를 CSV로 변환하며 나오는 에러를 고치는 작업을 반복했다.
- IMPORT INTO는 실행하는 동안 테이블을 오프라인으로 만들고, 키 충돌이 하나라도 나면 전부 Revert한다. 이 제약을 확인한 팀은 이튿날 오후 12시부터 중복을 없애 데이터베이스에 바로 넣을 수 있는 하나의 큰 CSV 파일로 병합하는 Spark 코드를 작성했다.
- 스토리지가 넉넉한 새 데이터베이스 클러스터에 데이터를 넣기 시작했고, 시간이 너무 오래 걸릴 것으로 보여 유저마다 가장 최근 스냅샷 1개와 가장 최근 저널 300개만 복원하기로 범위를 좁혔다.
- 서비스 재개에 쓸 깨끗한 클러스터를 따로 준비해 저널, 스냅샷, 유저 테이블 외의 테이블은 백업에서 복원했다. 저널과 스냅샷 테이블은 전처리한 CSV에서 Import했고, 유저 테이블은 서버 로직으로 다시 만들어 오후 8시에 모든 작업을 마쳤다.
- 일부 유저를 샘플링해 분석 로그에 기록된 상태와 최종값이 같은지 검증했고, 모든 유저의 스냅샷 리플레이가 정상적으로 동작하는지 검증했다.
- 이튿날 23시 37분, 30시간 50분 만에 서비스를 다시 열었다.
- 부하로 장애가 난 DevPlay 플랫폼의 AWS RDS 데이터베이스를 일시적인 순단을 감수하고 Failover해 정상화했다.
- 공식 백업과 복원 기능으로 데이터를 옮겨 기존 m5d 인스턴스를 더 많은 대수로 쓰는 세 번째 데이터베이스 클러스터를 구성했다. CockroachDB 서포트 엔지니어들과 논의해 TPC-C 벤치마크에 쓰는 것과 비슷한 설정값을 적용해 데이터를 옮기는 시간을 줄였다.
- 오전 8시 30분, 총 점검 시간 36시간 29분 만에 임시점검을 끝냈다.
- 후속 조치
- 프로덕션 인프라 작업은 아무리 사소해도 반드시 작업자 2명 이상이 참여하도록 규칙을 바꿨다.
- 작업에 쓸 스크립트와 작업 시나리오를 엄격하게 작성해 미리 팀 안에 공유하고 리뷰를 받도록 했다.
- 교훈
숙련된 작업자도 사람인 이상 실수할 수 있으므로, 실수를 막으려면 사람에게 기대지 말고 시스템을 갖춰야 한다. 복구할 수 있었던 바탕은 세 가지였다. 작업자 개인을 탓하지 않고 대응 과정을 기록해 액션 아이템을 정하는 장애 대응 원칙이 있었고, 과거 장애 경험이 기록으로 쌓여 있었으며, 인프라 운영과 데이터 분석을 맡는 팀이 한 조직에 있었다.
IL-0218복제를 다시 맞추다 PostgreSQL 프라이머리의 데이터 디렉터리가 지워지고 백업이 작동하지 않아 GitLab.com 이 약 18시간 멈추고 데이터를 잃었다GitLab2017- 증상
2017년 1월 31일 19:00 UTC 무렵 GitLab.com 의 데이터베이스 부하가 올랐고, 많은 사용자가 이슈와 머지 리퀘스트에 댓글을 달지 못했다. 스팸으로 의심되는 부하였고, 잡는 데 몇 시간이 걸렸다.
- 촉발
1월 31일 23:00 UTC 무렵 데이터베이스 부하로 세컨더리의 복제가 멈췄고, 세컨더리를 다시 맞추던 엔지니어가 세컨더리가 아니라 프라이머리에서 PostgreSQL 데이터 디렉터리를 지웠다.
- 원인
- 구성 요소
- 기여 요인
- 감지
프라이머리에서 데이터 디렉터리를 지운 엔지니어가 스스로 실수를 알아채고 1~2초 만에 삭제를 멈췄다.
- 조치
- pg_basebackup 이 복제 연결이 모자라다고 알리자 max_wal_senders 를 기본값 3 에서 32 로 잠시 올렸고, PostgreSQL 이 재시작을 거부하자 max_connections 를 8000 에서 2000 으로 낮췄다.
- 엔지니어가 프라이머리에서 데이터를 지우고 있다는 것을 알아채고 1~2초 만에 삭제 작업을 멈췄지만, 약 300 GB 가 이미 지워졌다.
- 데이터 손실을 가장 줄일 수 있는 유일한 방법으로 장애 6시간 전에 만든 LVM 스냅샷을 쓰기로 하고, 스테이징의 PostgreSQL 데이터 디렉터리를 약 18시간 동안 운영으로 복사해 복원했다.
- 웹훅 삭제를 거치지 않은 별도 스테이징 데이터베이스를 LVM 스냅샷으로 띄워 웹훅 테이블의 SQL 덤프를 만들고, 복원한 GitLab.com 데이터베이스에 가져왔다.
- 장애 전에 쓰였을 수 있는 ID 를 다시 쓰지 않도록 모든 데이터베이스 시퀀스를 100,000 씩 올렸다.
- GitLab.com 을 차례로 다시 열었다.
- 17:20 UTC 이후에 만든 프로젝트는 NFS 클러스터에 남은 Git 저장소로 가장 기본적인 형태만 복원했고, 이슈와 머지 리퀘스트 같은 데이터는 되살리지 못했다.
- 후속 조치
- 모든 호스트의 셸 프롬프트인 PS1 을 고쳐 호스트와 환경을 더 분명히 구분한다.
- 백업을 Prometheus 로 모니터링한다.
- PostgreSQL 의 max_connections 를 알맞은 값으로 둔다.
- PostgreSQL 의 시점 복구와 연속 아카이빙을 검토한다.
- 운영 데이터베이스의 LVM 스냅샷을 매시간 뜬다.
- 운영 데이터베이스에 Azure 디스크 스냅샷을 켠다.
- 스테이징을 ARM 환경으로 옮긴다.
- 운영 복제본을 되살린다.
- PostgreSQL 백업 복원을 자동으로 시험한다.
- PostgreSQL 복제 문서와 런북을 고친다.
- PostgreSQL 백업에 pgbarman 을 쓸지 검토한다.
- 데이터베이스 백업과 실시간 복제에 WAL-E 를 쓸지 검토한다.
- 스트리밍 방식의 데이터베이스 복원을 만든다.
- 데이터 내구성을 책임질 담당자를 정한다.
- 세컨더리를 여러 대 두고 부하를 나누도록 pgpool-II 3.6.1 을 묶고 PostgreSQL 연결 풀링과 부하 분산을 구성한다.
- 개발자가 데이터베이스 마이그레이션을 시험할 수 있도록 스테이징에서 Rails 마이그레이션을 실행하고 되돌리는 도구를 만든다.
- 데이터베이스뿐 아니라 GitLab.com 인프라 전체의 복구 절차를 만들고 그 절차의 담당자를 정한다.
- 공개 백업 모니터링 대시보드를 만들었고, 지금은 pg_dump 백업 데이터만 있지만 데이터를 더 넣는다.
- 어뷰징 신고와 대응 시스템을 고쳐 스팸 신고로 사용자를 지울 때 데이터를 바로 영구 삭제하지 않게 한다.
- 앞으로 공개하는 장애 문서에서는 엔지니어의 이름을 가린다.
- 교훈
GitLab 은 장애를 GitLab.com 이 약 18시간 멈춘 문제와 복원이 18시간 넘게 걸린 문제로 나눠 5 Whys 로 분석했다. 세컨더리를 다시 만드는 작업은 자동화되지도 제대로 문서화되지도 않아 손으로 해야 했다. 표준 백업은 PostgreSQL 버전이 맞지 않아 조용히 실패했고, 실패 알림 메일은 DMARC 서명이 없어 거부됐다. 다른 백업 절차를 믿고 Azure 디스크 스냅샷을 켜지 않았다. 백업 절차를 맡은 사람이 없어 아무도 정기적으로 시험하지 않았다. GitLab 은 운영 엔지니어가 특정 명령을 못 쓰게 막는 것보다 재해 복구를 고치고 지금 어느 호스트를 쓰는지 더 분명히 보이게 하는 데 집중하기로 했다. rm 을 더 안전한 별칭으로 바꾸면 실수로 지우는 것은 막지만 디스크 손상처럼 데이터를 잃는 다른 경우는 막지 못한다. 이상적인 환경은 실수해도 영향이 거의 없이 빠르게 복구할 수 있는 곳이고, 그러려면 복구 절차를 정기적으로 해 보고 변경을 쉽게 시험하고 되돌릴 수 있어야 한다.
이 2건에서 가장 많이 나오는 구성 요소: 데이터베이스, 클라우드 블록 스토리지. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.