IL-0496 Ably · 2020-06-11 (게시일)database
전역 복제 Cassandra 클러스터에서 모든 리전의 인스턴스 CPU 가 100% 로 치솟아 쿼리가 타임아웃됐고, 같은 부하가 이틀 저녁 더 찾아왔다
Ably 는 메시지와 일부 메시지 메타데이터를 전 세계에 분산되고 복제된 Cassandra 클러스터에 저장한다. 푸시 기기 등록 기록의 샤딩 전략에서는 파티션 크기를 상수 시간에 세려고 카운터 컬럼을 썼고, 이 기능은 약 2년 동안 운영에서 쓰였다. 카운터 컬럼은 카운터 컬럼만 있는 테이블에만 둘 수 있고, 한 번 만든 카운터 테이블은 지울 수 없으며, 카운터 갱신은 멱등이 아니다. Ably 는 근사치면 충분하다고 보고 이 제약을 받아들였다.
2020년 초 사흘 저녁에 걸쳐 리전마다 Cassandra 인스턴스 여러 대의 CPU 가 100% 로 치솟고 전 세계에서 쿼리가 타임아웃됐다. 첫날은 21:22에 시작해 21:32에 가라앉았고, 다음 날 같은 시각에 다시 일어나 10분 만에 가라앉았다. 팀은 노드를 늘리고 노드 크기를 키웠지만 효과가 거의 없었다. 세 번째 날 API 층에 넣은 계측으로, 고객 계정 하나에서 한 가지 작업 요청이 대량으로 들어온 것을 찾았다. 요청마다 Cassandra 쿼리 여러 개와 카운터 테이블 갱신 하나가 따랐다. 몇 초 넘게 걸리는 쿼리를 다시 보내는 공격적인 재시도 때문에, 부하가 어느 선을 넘자 요청이 수백만 건으로 불었다. 다른 곳의 버그로 이 요청에는 외부 API 요청마다 걸리는 속도 제한이 걸리지 않았다. 이 고객의 애플리케이션은 매일 같은 시각에 다시 등록하는 셋톱박스 기기를 많이 두고 있었다.
팀은 이 요청에 속도 제한을 걸어 장애를 멈췄다. 재시도로 불어나기 전의 부하가 왜 Cassandra 응답 시간을 그렇게 떨어뜨렸는지는 여전히 남은 질문이었다. 카운터 컬럼을 쓰지 않는 다른 요청은 훨씬 높은 비율에서도 이런 부하를 만들지 않았으므로 팀은 카운터 컬럼을 원인으로 의심했다. 팀은 그 데이터의 Cassandra 레이아웃을 다시 설계해 카운터 컬럼을 전혀 쓰지 않는 샤딩 전략으로 바꿨다. 며칠 뒤 이 변경을 배포하자 Cassandra 인스턴스의 부하가 100분의 1 수준으로 줄었다. Ably 는 이후 조사에서 카운터 컬럼이 최종 일관성조차 보장하지 않는다는 자료를 확인했다.
- 심각도
- –
- 영향 범위
- Ably's primary realtime messaging service: operations that need a Cassandra lookup, such as the first use of an application in a given location and the persistence of some access tokens, failed
- 영향 사용자
- some customers were significantly affected
- 지역
- all regions
- 감지까지
- –
- 복구까지
- –
증상
운영 알람이 전 세계에서 Cassandra 쿼리의 상당 부분이 타임아웃된다고 알렸다. 리전마다 Cassandra 인스턴스 여러 대의 CPU 가 100% 에 붙어 있었고 운영 클러스터 전부가 영향을 받았다.
장애는 Ably 의 주력 실시간 메시징 서비스에 영향을 줬다. 메시지 처리 대부분은 Cassandra 를 거치지 않지만, 어떤 위치에서 애플리케이션을 처음 쓸 때나 일부 액세스 토큰을 저장할 때처럼 데이터베이스 조회가 필요한 작업은 실패했다. 이 실패로 일부 고객이 크게 영향을 받았다.
첫 장애는 21:22에 갑자기 시작해 21:32에 똑같이 갑자기 가라앉았다. 정확히 24시간 뒤 같은 일이 다시 일어났고 10분 뒤 가라앉았다. 그다음 날 21:22에 부하가 또 왔다.
팀은 먼저 트래픽을 다른 곳으로 돌려 피할 수 있는지 봤지만, 모든 리전과 모든 클러스터의 Cassandra 층이 영향을 받고 있어 소용이 없었다. 들어오는 요청 통계에서는 특정 요청 종류가 치솟은 흔적이 없었다. 트래픽의 출처를 막을 방법이 보이지 않았고, 외부 부하가 원인인지도 분명하지 않았다.
첫 장애 뒤 하루 동안 팀은 업데이트와 repair 를 돌리고 통계를 뒤졌지만 뚜렷한 증거를 찾지 못했다. 노드를 늘리고 노드 크기도 키웠지만 두 번째 장애가 그대로 왔고, 이때도 지표에서 수요 급증은 보이지 않았다. 다음 24시간 동안 팀은 Cassandra 위의 API 층에 계측을 더하고 영향받는 인스턴스에서 DTrace 로그를 받을 준비를 했다. 클러스터도 쓸 수 있는 가장 큰 인스턴스와 볼륨으로 다시 키웠다. 세 번째 부하 때 클러스터는 완전히 포화되지는 않았다.
원인
- 촉발
- 매일 같은 시각에 다시 등록하도록 프로그램된 셋톱박스 기기를 많이 둔 고객 계정 하나가 한 가지 작업 요청을 대량으로 보냈다. 몇 초 넘게 걸리는 쿼리를 다시 보내는 공격적인 재시도와, 이 요청에만 외부 API 속도 제한이 걸리지 않던 버그 때문에 요청 수백만 건이 Cassandra 층까지 닿았다.
감지
21:22에 운영 알람이 전 세계에서 Cassandra 쿼리의 상당 부분이 타임아웃된다고 알렸다.
조치
- 대량으로 들어오던 그 요청에 속도 제한을 걸어 Cassandra 장애를 멈췄다.
- 그 데이터의 Cassandra 레이아웃을 다시 설계하고 카운터 컬럼을 전혀 쓰지 않도록 샤딩 전략을 바꿔 며칠 뒤 배포했다. Cassandra 인스턴스의 부하가 100분의 1 수준으로 줄었다.
후속 조치
–
교훈
Ably 가 얻은 교훈은 이론과 실제가 다르다는 것이었다. 규모가 커지면 이론적인 고려 말고도 부하, 용량, 용량을 넘었을 때 벌어지는 일, 서비스가 예상대로 응답하지 않을 때 이웃 시스템이 어떻게 반응하는지를 따져야 한다. 모든 시스템은 아래 층 시스템 위에 만들어지고, 그 시스템들의 설계에도 이론과 실제 사이의 절충이 있어 언젠가는 예상하지 못한 동작이 나온다. Ably 는 Cassandra 카운터 컬럼을 쓰지 말라고 결론지었다.
출처
참고 문서
관련 사례
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0288CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다CDN77 · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0305Intercom 의 PlanetScale 샤드 하나에서 복제본이 CPU 100% 로 주 데이터베이스를 따라가지 못해 받은편지함에 최대 2.2시간 전의 데이터가 보였다Intercom · 2026같은 원인 · 공통 데이터베이스
IL-0390PostHog US Cloud 의 Persons Postgres 데이터베이스 쓰기가 크게 느려져 이벤트와 persons 수집이 최대 2일 지연됐다PostHog · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0287Atlas 와 Cloud Manager 의 모니터링을 받치는 내부 데이터베이스 클러스터의 샤드 하나가 과부하되어 지표 수집과 클러스터 작업이 늦어졌다MongoDB · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0298Wikimedia sessionstore 의 Cassandra 노드가 디스크가 가득 차 잇따라 죽고 쿼럼을 잃어 편집이 실패했다Wikimedia Foundation · 2025같은 원인 · 공통 데이터베이스
IL-0312max_connections 를 올리려고 재시작한 주 PostgreSQL 데이터베이스가 다시 올라오지 않아 Gadget 의 모든 앱 요청이 멈췄다Gadget · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0110Grafana Agent 파드가 메모리를 많이 쓰던 노드에 Hangfire 파드가 함께 올라가 시스템 OOM 으로 CrashLoopBackOff 를 반복했고, 노드가 응답을 멈추고 NotReady 가 됐다.DFDS · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0202갑자기 몰린 쿼리와 데이터베이스 쓰기로 Honeycomb 수집 호스트가 메모리 부족으로 죽었고, 쿠버네티스 CrashLoopBackOff 가 용량 회복을 막아 US1 이벤트 수집이 한 시간 넘게 불안정했다Honeycomb · 2023 · sev1같은 원인 · 공통 데이터베이스
IL-0386Google Cloud 로 옮긴 뒤 GKE 노드에서 Postgres 연결 타임아웃과 memcached i/o timeout 이 간헐적으로 튀었다incident.io · 2023같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0206GKE 파드 안의 Consul 에이전트가 메모리 급증으로 거듭 OOM kill 되어 Rails 파드가 데이터베이스 복제본을 찾지 못했고, 모든 쿼리가 primary 로 몰려 GitLab.com 이 느려졌다.GitLab · 2022같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0443Aurora MySQL reader 가 이유 없이 재시작한 뒤 writer 의 insert latency 가 7배쯤 오르고 replication lag 가 하루 넘게 이어졌다Repro · 2019같은 원인 · 공통 데이터베이스
IL-0037imagePullPolicy가 Always인 DaemonSet이 크래시 루프를 돌며 이미지를 계속 받아, NAT 세 대를 같이 쓰던 리전 전체가 이미지 레지스트리에서 429로 막혔다Datadog · 2019같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0211Mandrill 의 PostgreSQL 샤드 하나가 트랜잭션 ID 랩어라운드를 막으려고 쓰기를 멈춰 약 40시간 동안 메일 발송이 줄었다Mailchimp · 2019같은 원인 · 공통 데이터베이스
IL-0064CPU 를 많이 쓰는 파드가 Google Cloud 노드 하나에 몰려 노드가 커널 패닉으로 죽었고, 다시 배치된 파드가 다음 노드를 또 죽이며 웹사이트와 API 가 멈췄다.Moonlight · 2019같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0334RDS MySQL 의 bookmarks 테이블이 2TB 파일 크기 한도에 닿아 INSERT 가 실패하고 Instapaper 가 31시간 동안 멈췄다Instapaper · 2017같은 원인 · 공통 데이터베이스
IL-0333사양을 낮춘 RDS PostgreSQL 인스턴스가 피크 부하를 못 버텨 헬스 체크가 실패하고 Buildkite 대시보드가 몇 시간 동안 내려갔다Buildkite · 2016같은 원인 · 공통 데이터베이스
IL-0282US-East 리전의 DynamoDB 스토리지 서버들이 멤버십 정보를 받지 못해 스스로 요청 처리에서 빠지면서 고객 요청의 약 55% 가 실패했다Amazon Web Services · 2015같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0496
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0496/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.