IL-0589 Kickstarter · 2013-03-07databaseaws
Kickstarter 의 모든 MySQL 복제본이 중복 키 오류로 복제를 멈췄다
Kickstarter 는 관리형 MySQL 로 Amazon RDS 를 쓰고, RDS 의 기본 복제 모드는 MIXED 다. MIXED 모드는 평소에는 쿼리 자체를 넘기는 statement 기반 복제를 쓰다가, 복제본마다 결과가 달라질 수 있는 unsafe 쿼리를 만나면 잠시 행의 새 값 전체를 넘기는 row 기반 복제로 바꾼다.
Kickstarter 는 후원자가 후원을 마치면 프로젝트 안에서 겹치지 않고 차례로 늘어나는 순번을 매긴다. 경합 상태와, 중복 키 때문에 생기는 불필요한 롤백과 재시도를 피하려고, 백그라운드 작업이 사용자 정의 카운터 변수로 최근 후원의 순번을 한 번에 매기는 UPDATE 를 실행했다. 순서는 ORDER BY pledged_at ASC, id ASC 로 정했다. 데이터가 어긋난 시기에는 backings 테이블에 쓴 뒤 락을 기다리며 멈춘 트랜잭션들이 있었고, 이 트랜잭션들은 순서가 뒤바뀌어 끝났다. MySQL 은 트랜잭션의 쿼리를 COMMIT 때 binlog 에 쓰므로, primary 가 디스크에 쓴 행의 순서와 복제본이 binlog 를 다시 실행하며 쓴 순서가 달라졌다. 여기에 MySQL 이 가끔 ORDER BY 절을 무시하는 버그가 겹쳐, primary 와 복제본이 각자의 암묵적 순서로 순번을 매겼고 값이 어긋났다.
어긋난 데이터는 며칠에서 한 달 넘게 복제를 깨지 않았다. 나중에 unsafe 쿼리가 row 기반 복제를 일으키자 Update_rows 이벤트가 복제본의 고유 키와 충돌했고, 3월 7일 모든 복제본이 Error_code: 1062 로 멈췄다. 엔지니어들은 몇 시간에 걸쳐 사이트를 안정시키고 복구했지만, 그 뒤 같은 일이 다시 일어났다.
- 심각도
- –
- 영향 범위
- All MySQL replicas stopped updating; most of Kickstarter's traffic is served from the replicas
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
3월 7일 목요일, Kickstarter 트래픽 대부분을 받는 MySQL 복제본들이 갱신을 멈췄다. 복제본 하나만 멈췄다면 그 복제본을 갈아 끼우면 됐지만, 모든 복제본이 같은 상태였다.
SHOW SLAVE STATUS\G 의 출력에는 처음 보는 오류가 있었다. Last_Error: Could not execute Update_rows event on table kickstarter.backings; Duplicate entry '123456-789' for key 'index_backings_on_project_id_and_sequence', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin-changelog.169933, end_log_pos 12969124
오류가 가리킨 곳을 보니 primary 와 복제본의 값이 서로 다른 행 범위가 있었다. 이 데이터는 며칠 전부터 어긋나 있었고, 범위를 넓혀 찾자 한 달이 넘은 불일치도 나왔다. 어긋난 값은 몇몇 후원자 순번이었다.
엔지니어들은 몇 시간 동안 사이트를 안정시키고, 오래된 복제본 데이터의 영향을 줄이고, 사용자에게 알리고, 복구했다. 정상이라고 알린 뒤 같은 일이 처음부터 다시 일어났다.
증상 복제 지연
원인
- 촉발
- 데이터가 이미 어긋나 있는 상태에서, 나중에 실행된 unsafe 쿼리가 MIXED 모드 복제를 row 기반 복제로 바꿨다. 복제본이 그 행의 새 값을 그대로 쓰려다 고유 키가 겹쳐 복제가 멈췄다.
감지
트래픽 대부분을 받는 복제본들이 모두 갱신을 멈춘 것을 보고 알았고, SHOW SLAVE STATUS\G 에서 중복 키 복제 오류를 확인했다.
조치
–
후속 조치
–
교훈
데이터베이스는 복잡하다. Rails 커뮤니티에서는 데이터베이스를 ActiveRecord 와 ActiveRelation 뒤에 숨은 단순한 데이터 저장소로 여기기도 하지만, 데이터베이스가 요청받은 일을 어떻게 처리하는지 더 깊이 알아야 한다.
출처
관련 사례
IL-0281PostHog US 리전 Logs 제품의 ClickHouse 클러스터가 S3 에 둔 로그 데이터를 거의 다 지워 3일보다 오래된 로그가 사라졌다PostHog · 2026같은 원인 · 공통 데이터베이스 복제, 데이터베이스
IL-0527OpenStreetMap.org 의 복제 diff 생성이 invalid memory alloc request size 오류로 16시간 멈춤OpenStreetMap Foundation · 2025같은 원인 · 공통 데이터베이스 복제, 데이터베이스
같은 원인 · 공통 데이터베이스 복제, 데이터베이스
IL-0451Aurora MySQL 에서 인덱스를 INVISIBLE 로 바꿀 때마다 Reader 3대의 버퍼풀이 무효화돼 CPU 와 ReadIOPS 가 튀었다Daangn · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0150DynamoDB DNS 자동화의 경쟁 조건이 us-east-1 리전 엔드포인트의 DNS 레코드를 비워 DynamoDB 와 EC2 인스턴스 시작이 실패했고, 그 여파로 EKS, ECS, Fargate 의 컨테이너 시작과 클러스터 스케일링이 14시간 넘게 막혔다Amazon Web Services · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0329Postgres 17 업그레이드 뒤 다시 켠 PGAudit 가 마이그레이션 중 락을 쥔 채 멈춰, 서비스 전반이 느려지고 데이터베이스가 2분 동안 내려갔다incident.io · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스 복제
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0024무거운 API 요청이 MongoDB 에 과부하를 걸고 취소되지 않은 요청이 쌓여 Hugging Face Hub 가 사흘 동안 세 번 멈췄다Hugging Face · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0385큰 MySQL 테이블의 스키마 마이그레이션 마지막 단계에서 읽기 복제본 다수가 semaphore deadlock 에 걸려 GitHub 핵심 서비스가 2시간 50분 저하됐다GitHub · 2021같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0196Redis Operator 로 레플리카를 늘리면서 메모리 한도를 낮추자 데이터를 가진 유일한 Redis 파드가 재시작됐고, Sentinel 이 빈 레플리카를 마스터로 올려 데이터가 모두 지워졌다.Palark · 2020같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0388Redis 고가용 클러스터의 primary 노드가 내려간 뒤 Discord API 가 느려지고 길드 일부가 오프라인으로 보이며 접속이 실패했다Discord · 2017같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0589
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0589/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.