Incident Library

IL-0272 Monzo · 2019-07-29database

Cassandra 에 새로 넣은 서버가 데이터 없이 읽기와 쓰기를 맡아 데이터가 사라진 것처럼 보이면서 Monzo 의 로그인과 결제가 실패했다

Monzo 는 데이터를 Cassandra 클러스터 하나에 저장한다. 서버 21대로 이루어져 있고, 모든 데이터는 21대 가운데 세 대에 복제되며, 파티션 키가 어느 세 대가 그 데이터를 맡을지 정한다. 모든 읽기와 쓰기는 쿼럼으로 해서 세 대 가운데 적어도 두 대가 값을 확인해야 한다. 사용자와 마이크로서비스가 늘어 최대 부하 때 클러스터가 한계에 가까워지자 Monzo 는 클러스터를 키우기로 했다.

7월 29일 13:10 BST 에 새 서버 여섯 대를 넣었다. 팀은 새 서버가 클러스터에 들어온 뒤 데이터를 스트리밍할 때까지 비활성으로 머문다고 믿었다. 2018년 10월 확장 뒤 운영 환경의 auto_bootstrap 을 false 로 바꿔 두었는데, 서버를 잃어 교체할 때 다른 서버에서 다시 만들지 않고 백업에서 복원하려는 것이었다. 그런데 이 플래그는 데이터 스트리밍뿐 아니라 새 서버가 활성으로 들어오는지도 정한다. 새 서버들은 맡을 파티션을 정하자마자 데이터 없이 그 파티션을 완전히 맡아 질의를 처리했다. 그래서 일부 데이터가 사라진 것처럼 보였다. 시험 환경에서는 서버 한 대로만 시험했고, 한 대로는 나머지 두 대가 쿼럼을 맞춰 주므로 문제가 드러나지 않았다. 여섯 대를 넣자 일부 데이터의 담당 서버 세 대 가운데 두세 대가 새 서버로 바뀌었다.

그 결과 카드 결제 일부가 실패했다. 설정 서비스에서 키를 찾지 못한 internal edge 가 404 를 내 고객 응대 도구와 배포 도구가 멈췄다. 고객은 로그인, 결제, 잔액 확인을 제대로 하지 못했다. 팀은 Mastercard 서비스의 코드 오류를 고친 뒤 설정 서비스와 Cassandra 를 따라가 14:13 에 새 서버가 응답하고 있다는 것을 확인했다. 14:18 부터 새 서버를 한 대씩 빼 데이터 담당을 원래 서버로 돌렸다. 한 대마다 8~10분이 걸렸다. 14:28 에 첫 서버를 빼자 404 가 곧바로 줄었고, 15:08 에 마지막 서버를 빼자 대부분의 고객에게 Monzo 가 정상으로 돌아왔다. 새 서버가 질의를 처리하는 동안 쓰인 데이터는 외부에 저장해 둔 이벤트를 재생하고 내부 정합성 확인 작업을 돌려 23:00 까지 바로잡았고, 데이터는 모두 복구됐다.

심각도
–
영향 범위
Monzo app logins, payments, ATM withdrawals, balances and transactions shown in the app, in-app chat and phone support; a small percentage of card transactions failed
영향 사용자
Monzo customers; most were working again at 15:08 and all at 23:00
지역
–
감지까지
4m
복구까지
9h 50m

증상

2019년 7월 29일 13:14 BST 에 Mastercard 카드 거래 일부가 실패한다는 자동 알림이 울렸다. 같은 시각 고객 응대 팀이 고객과 소통하는 도구가 제대로 동작하지 않아 앱 채팅으로 고객을 도울 수 없다고 알려 왔다.

고객은 앱에 로그인하지 못하거나, 결제와 송금을 주고받지 못하거나, ATM 에서 돈을 찾지 못했다. 앱에 잔액과 거래 내역이 틀리게 보였다. 있어야 할 거래를 찾지 못해 잔액이 잘못 나온 것이다. 13:32 에는 Android 와 iOS 앱에서 일부 고객이 로그아웃된다는 신고가 들어왔다.

13:29 에 Monzo 직원이 내부 서비스에 접근할 때 쓰는 internal edge 가 HTTP 404 응답을 내는 것이 보였다. 13:33 에 Mastercard 수정을 배포하려 했지만 배포 도구도 실패하고 있었다.

데이터베이스를 바꾼 엔지니어가 13:24 에 조사에 들어와 Cassandra 확장이 원인일 수 있는지 논의했지만, 오류도 늘지 않았고 읽기·쓰기 비율도 그대로여서 그 가능성을 뺐다. 결제 팀은 Mastercard 서비스의 작은 코드 오류를 찾아 원인이라고 보고 고쳤다. 13:39 에 수정을 배포하자 카드 거래 성공이 곧바로 나아졌지만 완전히 정상이 되지는 않았다.

internal edge 는 설정 서비스로 요청이 사설 네트워크 대역에서 왔는지 확인한다. 13:48 에 설정 서비스에 직접 물어보니 그 키에 404 를 냈다. 그런데 지표에는 설정 서비스의 읽기와 쓰기가 성공하고 있었고, 다른 키들은 그대로 있었다. 증거가 서로 맞지 않았다.

14:00 에 설정 서비스를 거치지 않고 Cassandra 에 직접 물어 internal edge 가 쓰는 키가 Cassandra 에 없다는 것을 확인했다. 14:13 에 Cassandra 에 질의한 응답이 새 서버 가운데 하나에서 온다는 것을 확인했다. 불가능하다고 여긴 일이 실제로 일어나 있었다.

증상 데이터 저장소 읽기 불일치오류율 상승

원인

촉발
2019년 7월 29일 13:10 BST 에 Cassandra 클러스터에 새 서버 여섯 대를 넣었다. 운영 환경의 auto_bootstrap 플래그는 false 였다.

감지

13:14 BST 에 Mastercard 카드 거래 일부가 실패한다는 자동 알림이 울렸고, 같은 시각 고객 응대 팀이 고객 소통 도구가 동작하지 않는다고 알려 왔다.

조치

후속 조치

교훈

Monzo 는 Cassandra 운영 지식에 빈틈이 있었다. 롤링 재시작이나 서버 업그레이드는 자주 했지만 서버 추가는 드물었다. 시험 환경에서는 운영과 같은 규모로 시험하지 않아 여섯 대 대신 한 대로 시험했고, 쿼럼을 고려하지 못했다. Cassandra 가 원인임을 보여 주는 지표가 없어 대응이 늦었다. 클러스터 하나로 모든 서비스를 돌리면 변경 하나의 영향이 넓고 장애 원인을 짚기도 어렵다. 이번에는 첫 알림부터 Cassandra 를 원인으로 짚기까지 거의 한 시간이 걸렸다.

출처

관련 사례

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

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

AI 도구와 스크립트용

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