Incident Library

IL-0565 Devsisters · 2022-12-22 (게시일)databaseaws

쿠키런: 킹덤의 CockroachDB 클러스터가 노드 24대 중 16대의 파일 시스템을 잃고 멈춰 게임이 36시간 넘게 점검에 들어갔다

쿠키런: 킹덤을 출시한 뒤 사용자 수가 계속 늘어 CockroachDB의 스토리지 사용량이 빠르게 늘었다. 첫 주말을 넘긴 월요일에 계산해 보니 이대로면 약 36시간 뒤 디스크가 가득 차 쓰기가 멈출 상황이었다. 팀은 CockroachDB 19.1.11 공식 가이드가 권하는 대로 공간을 미리 차지해 두는 더미 파일인 Ballast 파일을 만드는 스크립트를 실행했다. 클러스터는 로컬 스토리지 디바이스가 두 개인 m5d.8xlarge 24대였고, EC2는 둘 중 하나를 임의로 Primary Mount로 정한다. 설정 문제로 지정 경로가 Primary Mount에 해당한 노드 16대에서 스크립트가 파티션을 덮어썼고, 과반 노드를 잃은 클러스터 전체가 멈췄다. 데이터는 7개 복제본으로 저장하도록 설정돼 있었다.

팀은 쿠키런: 킹덤 개발팀과 논의해, 다른 방법이 있는 한 백업 시점 이후의 데이터를 잃는 백업 복원은 쓰지 않기로 했다. 목표는 장애 직전까지의 모든 데이터를 되살리는 것이었고, 팀은 세 방법을 동시에 진행했다. 운영체제 수준에서 노드를 복원하는 Plan A는 실패했다. 최신 백업에 분석용 로그를 다시 적용해 사용자 상태를 재현하는 Plan C는 핵심 API부터 손댔다. 남은 노드 7대의 SST 파일에서 데이터를 직접 꺼내는 Plan B가 성공했다. 팀은 데이터를 완전히 잃을 확률을 약 3.3%로 계산했다. 또 CockroachDB 소스코드에서 SST 파일 내부를 보는 명령을 찾아 파일 구조를 해독했다. Spark로 약 7.5TB의 SST 파일을 CSV로 추출했고, 중복을 없애 하나의 CSV로 병합했다. 새 클러스터에는 유저마다 가장 최근 스냅샷 1개와 저널 300개만 넣었다. 저널과 스냅샷 테이블은 오후 4시 20분과 4시 57분에 복원됐다. 유저 테이블은 오염이 심해 서버 로직으로 다시 만들었다. 복원한 데이터는 백업으로 만든 데이터베이스와 대조했고, 샘플 유저 검증, 전체 유저 스냅샷 리플레이 검증, 사내망 테스트를 거쳤다. 서비스는 이튿날 23시 37분, 30시간 50분 만에 다시 열었다.

오래 기다린 유저들의 요청이 몰리며 DevPlay 플랫폼 데이터베이스가 연쇄적으로 장애를 일으켰고, AWS RDS Failover로 정상화했다. 새로 구성한 킹덤 클러스터는 i3 계열 인스턴스였다. 지표로 보면 이 클러스터에서 Disk Write Ops 부하가 CPU 부하로 이어졌고, 새벽 2시 42분에는 모든 쿼리가 실패해 2차 긴급 점검에 들어갔다. 팀은 공식 백업과 복원 기능으로 데이터를 옮겨 기존 m5d 인스턴스를 더 많은 대수로 쓰는 세 번째 클러스터를 만들었고, 오전 8시 30분에 총 36시간 29분 만에 점검을 끝냈다. 이후 CockroachDB도 안전장치를 개선했고, 21.2 이상 버전은 Ballast 파일을 자동으로 만든다.

심각도
–
영향 범위
Cookie Run: Kingdom was in emergency maintenance for 36 hours 29 minutes in total; the CockroachDB cluster holding user data was lost and rebuilt from data extracted from the surviving nodes
영향 사용자
Cookie Run: Kingdom players; the restored data belonged to users numbering in the millions
지역
AWS Tokyo region
감지까지
–
복구까지
36h 29m

증상

Ballast 파일을 만드는 스크립트를 실행한 직후 에러율, 데이터베이스 연결, Health Check 알람이 수백 건 한꺼번에 울렸다. 알람 메시지를 읽기도 전에 다음 알람이 쏟아졌고, 정상적인 게임 이용이 어렵다고 본 팀은 16시 52분에 긴급 점검을 시작했다.

커널 작업 화면은 빨간 글씨로 가득했다. 데브옵스 팀 전체가 약 30분 동안 셸 히스토리, CRDB 로그, 커널 로그, CRDB 소스코드를 분석한 뒤에야 무슨 일인지 알았다. 스크립트가 노드 24대 중 16대의 파티션을 덮어써 파일 시스템이 불안정해졌고, 쓰기에 실패한 노드들은 클러스터에서 자동으로 격리됐다. CockroachDB는 Raft 합의 알고리즘으로 동작해 과반 노드가 있어야 하므로, 노드 단위의 장애가 클러스터 전체의 장애로 번졌다.

팀은 먼저 AWS EC2 기술지원에 가상머신 스냅샷이 남아 있는지 물었지만 그런 것은 없었다. 영향받은 머신마다 EBS를 붙이고 dd 명령으로 파티션을 복제한 뒤 fsck를 돌렸지만 오류 항목이 너무 많았다. fsck 결과로 클러스터를 다시 띄워 봐도 특정 SST 파일을 찾을 수 없다는 식의 파일 시스템 오류가 남았다.

복구를 시도하던 23시 02분쯤 영향을 받지 않은 정상 노드 하나가 Host Status Failure로 내려갔다. 이 노드는 EBS 복제도 해 두지 않은 상태여서 남은 노드는 8대에서 7대로 줄었다.

남은 7대만으로 클러스터를 다시 구성하려 했지만, 클러스터가 시작할 때 Raft Quorum을 검증하는 로직이 영향받은 노드들의 기록 때문에 Healthy State로 넘어가지 못했다. 문서화되지 않은 내부 툴까지 써 봤지만 다음날 오전 5시까지 이 단계를 우회하는 방법을 찾지 못했다.

30시간 50분 만에 서비스를 다시 열자, 서버가 언제 열리는지 계속 확인하던 유저들의 요청이 로그인과 인증을 맡는 DevPlay 플랫폼에 몰려 플랫폼 데이터베이스 장애로 이어졌다. 이어 요청이 많은 자정 무렵부터 킹덤 데이터베이스에서 DB Timeout 에러가 관측됐고 일부 노드의 CPU가 100%에 이르렀다. 새벽 2시 42분에는 데이터베이스의 모든 쿼리와 요청이 실패해 2차 긴급 점검에 들어갔다.

증상 서비스 중단데이터 유실데이터베이스 과부하

원인

촉발
디스크가 가득 찰 때를 대비해 Ballast 파일을 만드는 스크립트를 실행했는데, 파일 경로가 잘못 설정돼 Block Device를 가리켰다. 이 명령에는 대상 경로에 파일이 이미 있는지 확인하는 안전장치가 없어 파티션을 그대로 덮어썼다.

감지

작업 직후 미리 설정해 둔 메트릭으로 알았다. 에러율, 데이터베이스 연결, Health Check 알람이 수백 건 동시에 울렸다. 2차 장애는 새벽 2시 42분 데이터베이스의 모든 쿼리와 요청이 실패하는 것을 관측하고 알았다.

조치

후속 조치

교훈

숙련된 작업자도 사람인 이상 실수할 수 있으므로, 실수를 막으려면 사람에게 기대지 말고 시스템을 갖춰야 한다. 복구할 수 있었던 바탕은 세 가지였다. 작업자 개인을 탓하지 않고 대응 과정을 기록해 액션 아이템을 정하는 장애 대응 원칙이 있었고, 과거 장애 경험이 기록으로 쌓여 있었으며, 인프라 운영과 데이터 분석을 맡는 팀이 한 조직에 있었다.

출처

관련 사례

내 클러스터에도 있는지 확인하기

kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이 사례와 같은 상태를 점검합니다. 이 사례의 구성 요소: 데이터베이스. 점검 항목의 근거는 이 사례 같은 공개 보고서입니다.

AI 도구와 스크립트용

API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.