Incident Library

IL-0311 BattleMetrics · 2022-03-27database

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

BattleMetrics 는 계정, 서버, 플레이어 정보를 PostgreSQL 에 두고, 웹사이트와 백엔드 서비스가 이 데이터베이스 없이는 돌아가지 않는다. Postgres 는 트랜잭션 약 21억 개까지만 견디고 그 뒤로는 쓰기 명령을 받지 않으며, 주기적인 vacuum 으로 이 위험을 줄인다. BattleMetrics 는 autovacuum 정책을 두고 몇 년 동안 문제없이 썼지만, 트랜잭션 ID 크기를 확인하는 헬스 체크는 두지 않았다. 플레이어 식별자 테이블의 인덱스가 알 수 없는 이유로 손상됐고, 로그로 보아 약 한 달 전인 2022-02-26 에 생긴 것으로 추정했다. 이 손상은 사이트 성능에 영향이 없어 아무도 몰랐지만, vacuum 작업은 이 손상 탓에 모두 오류로 끝났다. 손상은 replica, 백업 서버, 데이터베이스 장애 때 쓰려고 둔 내려받기용 백업에도 복제됐다.

2022-03-27 3:23 UTC 에 주 데이터베이스가 wraparound 보호로 읽기 전용이 됐다. 팀은 replica 로 수동 장애 조치를 했지만 같은 상태가 복제돼 있어 소용없었다. 그다음 Postgres 서버 다섯 대 중 세 대로 세 가지 방법을 동시에 시도했다. 원래 primary 에서는 오류 문구대로 single-user mode 에서 전체 vacuum 을 돌렸고, 다른 한 대는 지우고 백업에서 복원을 시작했으며, 나머지 한 대에서는 Google Cloud 문서의 방법을 따랐다. 세 번째 방법이 통했다. wraparound 보호에 들어간 서버에서도 single-user mode 없이 전체 vacuum 을 돌릴 수 있었다. 팀은 vacuum 에 자원을 최대한 주도록 설정을 올리고 재시작한 뒤 vacuum 을 시작했다. 약 30분 뒤 vacuum 이 인덱스 오류로 취소되면서 손상된 인덱스가 드러났다. 팀은 데이터베이스를 내리고 single-user mode 에서 인덱스를 지운 뒤 다시 올려 vacuum 을 돌렸고, 이번에는 vacuum 이 성공해 데이터베이스가 쓰기를 다시 받았다. 수리에는 약 3시간이 걸렸다.

지운 인덱스를 다시 만드는 데 약 두 시간이 걸렸다. 서버 한 대로는 RCON 과 쿼리를 다 감당할 수 없어 쿼리 워커를 멈추고 RCON 업데이트를 우선했다. 인덱스가 돌아오자 서비스가 새 primary 를 가리키게 했다. 쿼리를 멈췄는데도 서버 한 대의 CPU, 디스크, 네트워크가 포화돼 RCON 은 크게 지연된 채로 돌았다. 첫 replica 는 primary 부하 때문에 부트스트랩에 3시간 44분이 걸려 12:40 UTC 에 올라왔고, 그때 밀린 업데이트는 66만 건이었다. replica 를 더 띄울 때마다 primary 부하가 줄어 16:30 UTC 에 RCON 업데이트를 따라잡았다. 그 뒤 RCON 이 늦어지지 않게 쿼리를 제한해서 다시 돌렸다. 플레이어 검색 색인은 16:46 UTC, Steam 프로필 조회는 17:53 UTC 에 따라잡았고, 00:42 에 모든 replica 가 돌아와 쿼리를 다시 최대 속도로 돌렸다.

심각도
–
영향 범위
The website, API and backend services that need Postgres, including RCON updates and queries; RCON updates ran heavily delayed for hours after the database was repaired
영향 사용자
BattleMetrics users; most servers kept RCON delay below 5 minutes on average, larger servers saw up to two hours
지역
–
감지까지
–
복구까지
21h 19m

증상

2022-03-27 3:23 UTC 에 계정, 서버, 플레이어 정보를 담는 주 PostgreSQL 데이터베이스가 쓰기를 받지 않았다. 처음 보인 증상은 사용자가 웹사이트를 불러오지 못하는 것이었다.

사용자용 API 키는 최대 15분 동안 유효하다. 키가 유효한 동안은 사용자가 웹사이트를 불러오고 정보를 볼 수 있었다. 키가 만료되면서 웹사이트를 불러오지 못한다는 신고가 늘었다. 곧 RCON 업데이트와 쿼리도 실패하기 시작했다.

데이터베이스 로그에는 다음 오류가 수천 번 반복됐다. ERROR: database is not accepting commands to avoid wraparound data loss in database "battlemetrics" HINT: Stop the postmaster and vacuum that database in single-user mode. You might also need to commit or roll back old prepared transactions, or drop stale replication slots.

문제가 시작되기 30분쯤 전에 작은 공격으로 DDoS 방어가 작동했기 때문에, 팀은 처음에 웹사이트 문제와 RCON 업데이트 및 쿼리의 실패를 그 공격 탓으로 보았다. 더 살펴보고 나서야 주 데이터베이스가 쓰기를 받지 않는 것을 찾았다.

replica 도 영향을 받았는지 알 수 없는 상태에서 replica 하나로 수동 장애 조치를 했지만 소용없었다. wraparound 직전의 트랜잭션 ID 와 아직 찾지 못한 데이터 손상이 replica 에도 복제돼 있었다.

최대한 자원을 준 전체 vacuum 은 약 30분 뒤 failed to re-find parent key in index "player_identifiers_type_identifier_index" for deletion target page 615856 오류로 취소됐다. 팀은 이 오류를 보고 플레이어 식별자 인덱스가 손상돼 그동안 autovacuum 이 실패해 왔다는 것을 알았다. 그 인덱스를 지우려 하자 다시 database is not accepting commands to avoid wraparound data loss in database 오류가 나왔다.

데이터베이스를 고친 뒤에도 Postgres 서버 한 대로는 부하를 감당하지 못해 CPU, 디스크, 네트워크가 모두 포화됐다. RCON 처리 지연은 P50 이 2분 30초였고 P90 과 P99 는 상한인 5분에 머물러 있었다. 로그를 보면 일부 서버는 최대 두 시간까지 지연됐다. 업데이트가 많은 서버일수록 더 늦어졌다.

증상 쓰기 거부서비스 중단

원인

촉발
플레이어 식별자 테이블의 인덱스가 알 수 없는 이유로 손상돼 vacuum 작업이 모두 오류로 끝났다. 로그로 보아 손상은 약 한 달 전인 2022-02-26 에 생긴 것으로 추정했고, 그동안 트랜잭션 ID 가 계속 쌓여 2022-03-27 에 wraparound 보호가 작동했다.

감지

처음 들어온 것은 웹사이트를 불러오지 못한다는 사용자 신고였다. 팀은 30분쯤 전에 작동한 DDoS 방어 탓으로 보았다가, RCON 업데이트와 쿼리가 실패하는 것을 보고 더 살펴본 끝에 주 데이터베이스가 쓰기를 받지 않는 것을 찾았다.

조치

후속 조치

교훈

BattleMetrics 는 Postgres 의 트랜잭션 ID 크기를 확인하는 헬스 체크를 두지 않은 것을 결정적인 실수로 보았다. 인덱스 손상은 사이트 성능에 영향이 없어 한 달 동안 드러나지 않았고, 그동안 vacuum 이 계속 실패하며 데이터베이스가 wraparound 에 다가갔다. 손상은 replica 에도 복제돼 있어 장애 조치가 소용없었고, 백업 서버와 내려받기용 백업도 같은 손상을 안고 있었다. 오류 문구와 달리 wraparound 보호에 들어간 서버에서도 single-user mode 없이 전체 vacuum 을 돌릴 수 있었다.

출처

참고 문서

관련 사례

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

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

AI 도구와 스크립트용

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