Incident Library
  • 원인
  • 구성 요소
  • 증상
  • 기여 요인
  • 사례

사례10건

10건 중 1~5번째

  1. 증상

    9월 27일 22:58 UTC 에 쿼리 큐 깊이 알림이 울렸다. Azure West Europe 리전 고객의 쿼리가 느려지고 타임아웃됐다. 쓰기는 계속 받았지만 일부 파티션에서는 새 데이터를 바로 조회할 수 없었다.

    원인
    구성 요소
    기여 요인
    감지

    9월 27일 22:58 UTC 에 쿼리 큐 깊이 알림이 울려 장애 대응이 시작됐다.

    조치
    • 쿼리 계층 용량을 두 배로 늘렸다.
    • 9월 28일 아침에 멈춘 스토리지 파드를 하나씩 재시작했다.
    • 9월 29일 08:58 UTC 에 readiness 검사 타임아웃을 올려 전체에 배포했다.
    • 재시작 뒤 복구 동시성을 두 배로 늘렸다.
    • 9월 30일 00:25 UTC 에 정리 타임아웃을 24시간으로 올려 안전장치가 일으키던 강제 재시작을 멈췄다.
    • 스토리지 파드마다 자원 요청을 올려 호스트에 올라가는 파드 수를 줄였고, 파드마다 페이지 캐시용 메모리와 디스크 처리량이 두 배가 됐다.
    후속 조치
    • 페이지 폴트 비율, 캐시 커버리지, 스토리지 볼륨의 디스크 읽기, 쿼리 중단 비율에 경고 알림을 더했다. 알림은 캐시 압박이 고객에게 보이기 전에 울리도록 만들었다.
    • 런북에 major page fault 를 스토리지 성능 저하의 선행 지표로 적고, 조정할 수 있는 완화 설정을 자세히 적었다.
    • 스토리지 엔진의 참조 누수를 계속 추적한다.
    • 디스크 검사를 상태 검사 경로에서 뺀다.
    교훈

    캐시가 모자란 상태는 메모리 지표에 드러나지 않았다. 스토리지 프로세스가 메모리를 적게 쓰고 나머지를 페이지 캐시가 차지하기 때문이다. InfluxData 는 major page fault 를 스토리지 성능 저하의 선행 지표로 본다. InfluxData 는 스토리지 엔진의 참조 누수와 상태 검사 경로의 디스크 검사가 이런 장애를 일으키는 위험 요인은 아니며, 진단과 복구 중에 눈에 띄어 조사할 만한 현상이라고 밝혔다.

  2. 증상

    2026-04-28 10:34 BST에 새 데이터베이스로 전환한 뒤 11:30 무렵 운영에서 데이터 이상이 보였다. 이전 직전에 쓴 짧은 기간의 데이터가 새 데이터베이스로 복제되지 않았고, 서비스는 전환 때부터 약 3시간 저하됐다.

    촉발

    2026-04-20 16:20 BST 무렵 관련 없는 설정 수정 작업 중에 자격 증명을 교체했다. 그 자격 증명으로 데이터베이스 연결을 잡고 있던 임시 일회성 복제 프로세스가 죽었고, 그 순간 처리 중이던 데이터 묶음이 버려진 뒤 다시 재생되지 않았다.

    원인
    구성 요소
    기여 요인
    감지

    2026-04-28 11:30 BST 무렵 운영에서 데이터 이상을 발견하고 조사를 시작했다. 8일 전의 손실은 그때까지 아무 신호도 없었다.

    조치
    • 근본 원인을 찾는 일보다 서비스의 정상 동작을 되살리는 일을 먼저 했고, 전환 약 3시간 뒤인 13:30 BST 무렵 정상 동작이 돌아왔다.
    • 버려진 묶음을 다시 재생할 원본으로 쓰려고 이전 사업자에게 지운 원본 데이터베이스의 복원을 요청했다.
    • 2026-04-29부터 2026-04-30까지 원본 데이터베이스를 복원하고 영향을 받은 사용자의 기록을 다시 재생했다. 이 동안 서비스는 더 멈추지 않았다.
    후속 조치
    • 위험도가 비슷한 기술 변경은 라이브 전환 대신 계획된 유지보수 시간 안에 한다. 트래픽을 다시 받기 전에 무결성을 확인할 수 있도록 짧은 계획 중단을 받아들인다.
    • 이런 변경에는 전환 전 점검표를 두고, 전환 직전에 데이터 복제나 동기화 프로세스가 살아 있고 따라잡았는지 확인한다.
    • 오래 도는 프로세스가 쓰는 서비스 계정의 자격 증명을 교체할 때는 그 뒤에 영향을 받을 곳을 명시적으로 검토한다.
    • 전환 뒤 대상 쪽의 무결성을 따로 확인하기 전에는 원본 시스템을 내리거나 지우지 않는다.
    • 계획된 유지보수와 이전을 고객에게 알릴 때 Discord와 함께 웹 콘솔에서 보이는 제품 안 News 피드에도 올리고, 영향을 분명히 적고, 이번보다 훨씬 일찍 알린다.
    교훈

    이전 작업 자체는 문제가 없었고, 실패는 8일 전 관련 없는 변경이 조용히 남긴 부작용이었다. 복제 프로세스가 다시 살아나 정상으로 돌았기 때문에 데이터를 잃었다는 신호가 없었고, 전환 전에 데이터 무결성을 확인했다면 트래픽을 다시 받기 전에 잡았을 것이다. 새 데이터베이스의 무결성을 확인하기 전에 원본 데이터베이스를 지운 탓에 복구가 크게 복잡해졌으므로 앞으로는 전환 뒤 확인이 끝날 때까지 원본을 남긴다. 중단을 줄이려고 고른 라이브 이전에는 트래픽이 돌아오기 전에 무결성을 확인할 틈이 없었다. 그 결과 약 3시간의 서비스 저하와 이틀의 복구가 이어졌고, 이는 계획된 유지보수로 서비스를 잠깐 멈췄을 때보다 훨씬 큰 영향이었다. Discord 공지는 영향이 분명하지 않았고 고객이 대비할 시간을 충분히 주지 못했다.

  3. 증상

    13:30 UTC 에 ZooKeeperWait 지표가 갑자기 오른다는 알림이 왔다. 이 클러스터의 알림 기준은 낮은 쪽 10초, 높은 쪽 20초인데 값은 수천 초였다. 값은 대칭으로 이중화된 인스턴스 세 곳에서 똑같이 올랐다.

    촉발

    몇 달 동안 네트워크에서 떨어져 있던 클라이언트 머신 두 대가 다시 연결되면서, 그동안 쌓인 몇 달 치 헬스 체크 데이터를 아주 작은 배치로 빠르게 보냈다.

    원인
    구성 요소
    기여 요인
    감지

    13:30 UTC 에 팀은 ZooKeeperWait 지표가 갑자기 오른다는 알림을 받았다. 이 클러스터 크기에 맞춘 알림 기준은 낮은 쪽 10초, 높은 쪽 20초였다.

    조치
    • 쌓인 파트를 끝내 정리하지 못한 5분 단위 파티션 테이블을 장애 뒤 DROP-CREATE 로 다시 만들어 정상으로 되돌렸다.
    • 그 테이블의 파티션 단위를 분에서 시간으로 넓혔다.
    후속 조치
    • 루트 MaterializedView 테이블에서 범위를 벗어난 타임스탬프를 거부하도록 구현했다.
    • 두 번째 MaterializedView 가 거부된 데이터의 통계를 기록한다.
    • 거부 범위는 과거 데이터 백필을 위해 일부러 넓게 잡았고, 거부되는 데이터를 모아 가며 범위를 다듬는다.
    • 타임스탬프가 며칠이나 몇 달에 걸친 insert 쿼리 하나로 이번 상황을 재현하는 최소 시험 시나리오를 만들었다.
    • 관측 기능을 여러 가지 개선한다.
    교훈

    이 파이프라인은 주로 데이터 양을 다루지만, 어긋난 타임스탬프도 카디널리티 변화만큼 파이프라인을 흔들 수 있었다. 이상한 지표를 바로 설명하지 못했다고 치워 두면 안 된다. 이번에도 원인으로 이끈 것은 처음에 무시한 insert 크기 감소였다. 중앙값과 평균은 각자 쓸모가 있고, 이번에는 평균이 실마리였다. 파티션이 너무 적으면 파트가 커지고 mutation 이 느려지며 TTL 이 너무 비싸지거나 아예 동작하지 않는다. 반대로 너무 많으면 열 스캔과 집계 쿼리가 느려지고 Keeper 가 과부하된다. Keeper 작업은 파트 수에 따라 선형보다 훨씬 빠르게 늘었다.

  4. 증상

    Logs 클러스터의 노드 하나가 죽었고, 다시 시작하는 중에 찾을 수 없는 데이터가 너무 많아 뜨지 못했다. 엔지니어가 확인해 보니 S3 에 저장된 데이터 대부분이 없었다.

    촉발

    인덱스를 materialize 하는 일상적인 mutation 이 끝나면서 ClickHouse 의 zero-copy replication 버그가 터졌고, 복제본 하나가 데이터베이스의 모든 데이터 파트를 더는 아무도 참조하지 않는다고 잘못 판단했다.

    원인
    구성 요소
    기여 요인
    감지

    19:40 UTC 에 클러스터 노드 하나가 죽었고, 재시작하다 없는 데이터가 많아 뜨지 못했다. 엔지니어가 이를 조사하다 S3 에 저장된 데이터 대부분이 없는 것을 발견했다. 그 전 8시간 동안 자동 알람은 하나도 울리지 않았다.

    조치
    • zero-copy replication 을 쓰지 않는 새 테이블로 전환하고 최근 메시지를 따라잡았다.
    • 보존 기간 3일인 Kafka 기록에서 데이터를 새 테이블로 백필했다. 2월 20일 10:05 UTC 에 시작해 12:21 에 끝났다.
    후속 조치
    • 모든 클러스터에서 Zero Copy Replication 을 바로 끈다.
    • Logs ClickHouse 설정 전체를 감사하고 운영 환경에서 실험 기능을 쓰지 않게 한다.
    • 저장소 버킷에 S3 Versioning 을 켜서 데이터베이스가 버그로 파괴적인 명령을 내도 객체를 되살릴 수 있게 한다.
    • 제품을 정식 출시하기 전에 설정과 데이터 무결성 전략을 표본 점검한다. 이 점검으로 단일 장애 지점을 찾아 고친다.
    교훈

    Logs 제품을 따로 떼어 둔 덕분에 다른 제품과 기능은 전혀 영향을 받지 않았고, Kafka 보존 기간 3일 덕분에 최근 데이터는 잃지 않았다. 반면 MVP 와 알파 단계에 쓰려던 실험 설정이 운영 환경까지 그대로 남았다. PostHog 는 들어오는 데이터와 핫 데이터의 상태만 감시해 과거 데이터가 지워지는 것을 보지 못했다. 공유 저장소를 쓰면서 데이터 내구성을 데이터베이스 복제에만 맡겨 단일 장애 지점이 생겼고, S3 Versioning 이 없어 지워진 파일을 되살릴 수 없었다.

  5. 증상

    2024년 9월 18일 데이터센터 전환을 앞두고 cookbook 으로 원형 복제를 설정하던 중, 21:28 UTC 쯤 엔지니어가 x1 섹션의 primary master 가 복제를 하지 않는 것을 orchestrator 에서 먼저 알아챘다. es6 섹션도 같은 상태였다.

    촉발

    다음 주 데이터센터 전환을 앞두고 cookbook 이 핵심 데이터베이스를 eqiad 에서 codfw 로 가는 한 방향 복제에서 원형 복제로 바꿨다. ROW 기반 복제를 쓰는 x1 섹션에 codfw 에서 eqiad 로 가는 복제를 설정하고 pt-heartbeat 를 시작하자, eqiad 서버에 없는 heartbeat 행을 갱신하려다 복제가 멈췄다.

    원인
    구성 요소
    기여 요인
    감지

    원형 복제의 일반 모니터링이 아직 켜지지 않아, 엔지니어가 orchestrator 에서 먼저 알아챘다. 복제 자동화가 처음 도는 날이라 평소보다 많은 사람이 데이터베이스 상태를 지켜보고 있었다. 사용자에게 영향을 준 eqiad 에서 codfw 로 가는 방향의 고장은 Icinga 알림이 잡았다. 온콜 호출을 받은 사람은 없었다.

    조치
    • SET GLOBAL Replication_wild_ignore_table='heartbeat.%'; 로 heartbeat 테이블 복제를 건너뛰게 해 복제가 다시 흐르게 했다.
    • es 호스트에는 원래 고장이 난 방향에 맞춰, binlog 기록을 끈 채 eqiad 서버마다 빠진 codfw heartbeat 행을 직접 넣었다. 명령은 set sql_log_bin=0; INSERT INTO heartbeat.heartbeat (server_id, shard, datacenter) VALUES (<codfw-server-id>, 'es6' [or 'es7'], 'codfw'); 였다. es6 에서 먼저 시험했고, es7 에는 원형 복제를 설정하기 전에 미리 넣었다.
    • x1 codfw 호스트마다 binlog 기록을 끈 채 빠진 heartbeat 행을 넣어, 임시로 걸어 둔 heartbeat 무시 설정을 대신했다. 명령은 set sql_log_bin=0; INSERT INTO heartbeat.heartbeat (server_id, shard, datacenter) VALUES (<eqiad-server-id>, 'x1', 'eqiad'); 였다.
    후속 조치
    • 같은 문제를 다시 겪지 않게 한다. 빠진 행을 찾으면 직접 넣는 방식을 유력하게 본다.
    • 유지 보수 뒤 복제가 의도대로 양방향으로 동작하는지 확인하는 상태 점검을 cookbook 에 넣는다.
    • 유지 보수를 다른 순서로, 또는 섹션마다 따로 돌릴 수 있는 옵션을 더한다.
    • Phabricator 를 마지막에 한 번만 갱신하지 않고 섹션마다 갱신한다.
    • 모니터링의 빈틈을 메운다.
    • x1 과 ROW 를 쓰는 읽기·쓰기 es 호스트에서 pt-heartbeat-wikimedia 가 자기 세션을 STATEMENT 로 쓰도록 고쳐 배포했다.
    교훈

    원형 복제는 평소 운영 방식이 아니어서 heartbeat 테이블을 지우는 첫 조치가 문제를 eqiad 에서 codfw 로 옮기기만 했다. TRUNCATE 는 DDL 이라 늘 STATEMENT 모드로 전달되므로 이번에는 DELETE 보다 나았겠지만, 더 위험해서 고려하지 않았다. ROW 기반 복제, pt-heartbeat, 서버마다 다른 heartbeat 테이블 행이 겹친 문제는 이전 유지 보수 기록에 없었다. 자동화의 점검은 설정 직후 한 번이 아니라 모든 작업이 끝난 뒤에도 복제 채널을 확인했어야 했다. Wikimedia 는 어느 호스트에서도 sql_skip_slave_counter 를 쓰지 않아 더 큰 문제나 데이터 손실을 피한 것을 잘된 점으로 꼽았다.

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

이 10건에서 가장 많이 나오는 구성 요소: 데이터베이스 복제, 데이터베이스. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.

원인별6

용량 한계5건

  1. IL-0379 Azure West Europe 의 InfluxDB Cloud 에서 9월 27일부터 30일까지 쿼리가 느려지고 타임아웃됐다
  2. IL-0288 CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다
    CDN772026
  3. IL-0443 Aurora MySQL reader 가 이유 없이 재시작한 뒤 writer 의 insert latency 가 7배쯤 오르고 replication lag 가 하루 넘게 이어졌다
    Repro2019
  4. IL-0334 RDS MySQL 의 bookmarks 테이블이 2TB 파일 크기 한도에 닿아 INSERT 가 실패하고 Instapaper 가 31시간 동안 멈췄다
  5. IL-0296 Transloadit 의 us-east 리전 Redis 클러스터가 대역폭에 막혀 작업과 하트비트를 잃었다

인증서·자격 증명 만료1건

  1. IL-0490 관리형 데이터베이스에서 자체 MySQL로 옮긴 뒤 이전 직전에 쓴 기록이 새 데이터베이스에 없어 LootLocker 서비스가 저하됐다

소프트웨어 결함1건

조직
  1. IL-0281 PostHog US 리전 Logs 제품의 ClickHouse 클러스터가 S3 에 둔 로그 데이터를 거의 다 지워 3일보다 오래된 로그가 사라졌다

설정 변경1건

  1. IL-0392 데이터센터 전환을 앞두고 원형 복제를 설정하던 중 Wikimedia x1 섹션의 eqiad·codfw 사이 MariaDB 복제가 6분 멈췄다

업그레이드로 깨진 호환성1건

  1. IL-0308 RevenueCat 이 Aurora PostgreSQL 10 에서 14 새 클러스터로 넘어간 직후 쿼리가 극도로 느려져 대시보드와 SDK 엔드포인트가 세 시간 넘게 실패했다

데이터 손상1건

  1. IL-0311 주 PostgreSQL 데이터베이스가 트랜잭션 ID wraparound 보호로 읽기 전용이 되어 웹사이트와 백엔드 서비스가 멈췄다