Incident Library

IL-0308 RevenueCat · 2022-11-23databaseaws

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

AWS 가 Aurora PostgreSQL 10.x 지원을 2023년 1월 31일에 끝낸다고 알려 와, RevenueCat 은 주 데이터베이스 클러스터를 업그레이드해야 했다. 이번에는 데이터베이스 복제를 쓰기로 했다. 스냅샷을 새 클러스터에 복원해 Aurora PostgreSQL 14.x 로 올리고, 운영 클러스터의 변경을 복제해 따라잡은 뒤, 옛 클러스터를 잠깐 읽기 전용으로 바꾸고 새 클러스터로 페일오버하는 계획이었다. 44단계짜리 작업이라 두 달 넘게 준비하고 여러 번 사전 연습을 했다. 예상한 중단은 전체 중단 10초 미만, 부분 중단 1~2분이었다.

2022년 11월 23일 2:51 UTC 에 스냅샷으로 새 클러스터를 만들고 복제를 시작했고, 8:51 UTC 에 복제가 따라잡았다. 9:34 UTC 에 옛 클러스터를 읽기 전용으로 바꾸고 트래픽을 새 클러스터로 옮기기 시작했고, 9:39 UTC 에 트래픽 전부가 새 클러스터로 갔다. 곧바로 심각한 성능 저하가 왔다. 사전 연습 때는 14.x 클러스터가 충분히 오래 떠 있어 vacuum 이 끝나고 쿼리 플래너가 쓸 통계가 모여 있었지만, 이날은 가장 큰 테이블 하나의 vacuum 이 전환 전에 끝나지 않았다. ANALYZE 가 돌지 않은 가장 큰 테이블들에서 처리량이 많은 쿼리가 극도로 비효율적으로 바뀌었고, 이것이 모든 시스템에 연쇄 장애를 일으켰다.

팀은 9:54 UTC 에 데이터베이스 사용자에 statement timeout 을 걸고, 9:58 UTC 에 로드 밸런서에서 트래픽의 90% 에 503 을 보내 부하를 덜었다. 10:00 UTC 무렵부터 잘못 쓰이던 불필요한 인덱스를 지웠고, 10:30 UTC 무렵 트래픽의 50% 를 받을 수 있게 되었다. Apple 웹훅을 잠시 받지 않으면서 13:07 UTC 까지 트래픽을 100% 로 되돌렸다. New Relic 이 느린 쿼리마다 돌리던 EXPLAIN 쿼리를 없애려고 New Relic 을 끈 릴리스도 냈다. 12:00 UTC 무렵 많은 쿼리 플랜을 살핀 끝에 새 클러스터에서 ANALYZE 가 돌지 않았다는 것이 드러났고, 가장 큰 테이블들에 손으로 ANALYZE 를 돌리자 성능이 크게 나아졌다. 13:33 UTC 에 통합 이벤트 발송, ETL, 웹 서버 밖의 작업이 모두 돌아왔다. 그 밖에 시퀀스 상태가 복제되지 않아 큰 테이블 몇 개에서 기본 키가 겹쳤다. 또 전환 직후 통합 이벤트 발송을 멈추지 않아, 일부 이벤트는 발송되고도 기록되지 않았다. 팀은 롤백도 검토했다. 그러나 롤백은 복제 방향을 뒤집고 트래픽을 옛 웹 계층으로 되돌리는 복잡한 절차였고, 원인을 알았을 때는 대책을 모두 적용한 서비스가 꽤 잘 돌고 있어 그대로 수정을 이어 갔다.

심각도
–
영향 범위
The RevenueCat dashboard and the SDK endpoints failed or partly failed from 9:39 to about 13:07 UTC; entitlements for new purchases did not unlock or needed several attempts for about 2 hours; some integration events were dispatched without being recorded
영향 사용자
RevenueCat customers, and users of their apps who made new purchases or had expired entitlements
지역
–
감지까지
5m
복구까지
3h 33m

증상

2022년 11월 23일 9:39 UTC 에 트래픽 전부가 새 Aurora PostgreSQL 14.x 클러스터로 넘어갔고, 지연이 나빠져 인프라 팀이 조사를 시작했다. 9:54 UTC 에는 쿼리가 평소보다 훨씬 오래 걸리면서 데이터베이스 연결을 모두 차지하고 있었다.

RevenueCat 대시보드는 9:39 UTC 부터 13:07 UTC 무렵까지 열리지 않았고, SDK 가 쓰는 엔드포인트도 같은 시간 동안 문제를 겪었다. 11:30 UTC 무렵에는 요청의 절반쯤이 처리되었고, 13:07 UTC 에는 100% 가 처리되었다. 새 구매는 스토어에서는 성공했지만 2시간쯤 entitlement 가 풀리지 않거나 여러 번 시도해야 풀렸다. 이미 만료된 entitlement 를 가진 사용자는 장애 동안 접근을 잃었다.

데이터베이스 성능 문제가 모든 시스템에 연쇄 장애를 일으켜, 원인과 결과를 가려내는 데 1시간쯤 걸렸다. 처음에는 새 클러스터의 캐시가 아직 데워지지 않았기 때문이라고 보았다. 지난 24시간 동안 핵심 테이블에 들어온 레코드를 모두 읽어 캐시를 미리 데워 두었는데도 그렇게 판단했다. 데이터베이스가 데워져 IO 에 쓰는 시간이 줄자, 이번에는 완전히 포화된 것처럼 보이는 pg pool 클러스터를 의심했다. 느린 쿼리 때문에 빈 연결을 기다리는 pg bouncer 에 경합이 심했지만, 문제가 pg bouncer 인지 데이터베이스가 느린 것인지 분명하지 않았다.

느린 쿼리에 EXPLAIN 을 돌려 보니 쿼리 플랜이 극도로 비효율적이었다. 한 쿼리는 잘못된 인덱스를 쓰고 있었는데, ANALYZE 가 없어서인지 Postgres 14 쿼리 플래너가 다른 인덱스를 고른 것인지 분명하지 않았다. 다른 쿼리는 아주 단순한 경우에도 Postgres 가 뻔한 인덱스를 고르지 못했고, 이는 테이블 통계가 없다는 신호였다.

새 클러스터에서는 거의 모든 쿼리 뒤에 오래 걸리는 EXPLAIN 쿼리가 함께 실행되었다. 서드파티 APM 도구인 New Relic 이 느린 쿼리마다 EXPLAIN 을 돌렸고, 느린 쿼리가 많아지자 EXPLAIN 쿼리도 데이터베이스 자원을 많이 썼다.

트래픽을 다시 받기 시작하자 Apple 웹훅 요청이 들어왔다. 이 요청의 쿼리가 쿼리 플랜 문제로 특히 느려 복구가 다시 더뎌졌다. 큰 테이블 몇 개에서는 기본 키 시퀀스 값이 이미 테이블에 있는 행과 겹쳐 고유 제약 위반이 났다.

증상 데이터베이스 과부하지연 시간 증가서비스 중단커넥션 풀 고갈

원인

촉발
복제를 이용해 Aurora PostgreSQL 10.x 클러스터에서 새 14.x 클러스터로 트래픽을 넘겼다. 그런데 가장 큰 테이블 하나의 vacuum 이 전환 전에 끝나지 않아, 새 클러스터의 가장 큰 테이블들에 ANALYZE 가 돌지 않은 상태였다.

감지

9:39 UTC 에 트래픽 전부가 새 클러스터로 넘어갔을 때 지연이 나빠 보였고, 인프라 팀이 바로 조사를 시작했다.

조치

후속 조치

교훈

RevenueCat 은 처음부터 롤백했으면 더 나았다고 돌아봤다. 사전 연습에서는 데이터 일관성과 쿼리 성능만 보고 쓰기 트래픽을 재생하지 않았다. 쓰기는 인덱스가 얽히지 않아 읽기보다 단순하다고 여겼기 때문이다. 복제를 멈추고 평소처럼 쓰기를 해 봤다면 문제를 찾을 수 있었다. 시퀀스 상태가 복제되지 않는다는 한계를 놓치고 상태도 함께 복제된다고 가정했다. 사전 연습 때는 새 클러스터가 오래 떠 있어 vacuum 과 통계가 이미 끝나 있었기 때문에 ANALYZE 가 없는 문제를 보지 못했다. 시기로는 추수감사절과 블랙 프라이데이 전에 끝내려 했지만, 미국 지원팀 일부가 이미 휴가 중인 민감한 때였으므로 그다음 주로 미뤘어야 했다고 밝혔다.

출처

관련 사례

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

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

AI 도구와 스크립트용

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