Skip to content
isdnetworks
Go back

백업이 없던 데이터베이스에는 수명 정책보다 백업을 먼저 켜, 마지막 복구 지점을 지켰다

넘겨받은 커머스의 데이터베이스에 백업과 보존 정책을 걸면서, 집행 순서를 바꿔 백업부터 켜기로 했다. 백업을 점검하니 되돌릴 지점이 사실상 없었다. Firebase Realtime Database(RTDB)의 마지막 백업은 14.5개월 전이었고, Firestore 는 백업도 PITR(시점 복구)도 꺼져 있었다. 지금 데이터가 손상되면 RTDB 는 1년 전으로, Firestore 는 아무 데로도 돌아갈 수 없다.

Table of contents

Open Table of contents

배경 — 정책 부재가 아닌 누락

같은 프로젝트의 Cloud SQL(PostgreSQL 17)은 backupConfiguration.enabled = True 였고, 감사 로그에 cloudsql.instances.automatedBackup 이 매일 찍혀 있었다. 이 대조군 덕분에 「이 조직은 백업을 하지 않는다」가 아니라 「RTDB 와 Firestore 만 빠졌다」로 판정할 수 있었다. 정책을 새로 세우는 일이 아니라 누락을 메우는 일이라는 뜻이다.

백업 버킷에는 객체가 3개뿐이었다. 1년 전 RTDB 전량 백업(gzip 6.77GB)과 규칙 파일, 그리고 백업과 무관한 남의 이미지 파일 하나다. 버킷에는 lifecycle 도, retention 도, versioning 도 없었다.

해결 — Firestore 세 설정과 재조회

Firestore 는 승인을 받아 세 가지를 켰다.

세 가지 모두 명령이 성공했다는 메시지가 아니라, 설정을 다시 조회한 결과로 기록했다. 다만 삭제 보호가 실제로 삭제 명령을 거부하는지는 시험하지 않았고, 설정값 확인으로 갈음했다.

위험 지점 — 수명 정책을 먼저 걸면 생기는 일

RTDB 는 처음 세운 순서대로라면 「버킷에 30일 수명 정책을 먼저 걸고, 그다음 백업을 켠다」였다. 그런데 30일 lifecycle 은 앞으로 생길 객체만이 아니라 이미 30일을 넘긴 기존 객체에도 걸린다. 버킷의 객체 셋은 각각 439일·439일·288일이 지나 있었다. 정책을 거는 순간 그 자리에서 셋이 지워진다. 그중 둘은 지금 유일한 복구 지점이고, 나머지 하나는 우리에게 지울 권한이 없는 남의 파일이다.

그래서 RTDB 집행을 멈추고 순서를 다시 짰다. 후보는 셋이었다.

  1. 백업 설정에서 하위 폴더를 지정하고, lifecycle 을 matchesPrefix 로 그 폴더에만 건다
  2. 버킷 lifecycle 대신 백업 설정 안의 30일 수명 정책을 쓴다
  3. 백업을 먼저 켜고 새 백업 1벌을 확인한 뒤에 lifecycle 을 건다

1번이 가장 깨끗하다고 본 이유는 기존 객체를 건드리지 않고 새 백업만 30일로 관리되기 때문이다. 반면 3번은 새 백업을 확보한 뒤라 안전하지만, 그 대가는 기존 객체 셋이 지워지는 문제가 그대로 남는다는 점이다. 1·2번 중 무엇이 되는지는 콘솔의 백업 탭에 폴더와 수명 정책 칸이 있는지에 달려 있었다. RTDB 백업 켜기는 콘솔에서만 할 수 있어 담당자가 직접 눌러야 하는 일이었다.

측정 — PITR 저장량과 데이터 크기의 1:1

PITR 을 계속 켜 둘지는 비용으로 판단해야 했다. 처음 조사의 추정은 저장 비용이 거의 들지 않는다는 쪽이었는데, 7일 창이 가득 차기 전에 같은 방법으로 미리 재 보니 크게 빗나갔다.

Cloud Monitoring 메트릭실측
firestore.googleapis.com/storage/data_and_index_storage_bytes142.25 GiB
firestore.googleapis.com/storage/pitr_storage_bytes142.25 GiB
firestore.googleapis.com/storage/backups_storage_bytes시계열 0개

PITR 저장량이 데이터 크기와 바이트 단위까지 같았다. 같은 값이라 필터가 안 먹어 같은 시계열을 두 번 받은 것이 아닌지 의심했지만, 응답의 metric.type 이 각자 제 이름으로 찍혀 서로 다른 시계열이었다. 존재하지 않는 메트릭 이름으로 한 번 더 부르면 404 가 나는 것도 확인했다. 빈 결과와 조회 실패를 가르는 방법은 이 대조군뿐이다. Billing Catalog 의 단가로 보면 PITR 단가가 저장 단가와 같으므로, PITR 을 켜면 Firestore 저장 비용이 정확히 두 배가 된다. 처음 추정은 5~25배 빗나간 셈이다.

선택지도 생각보다 좁았다. gcloud firestore databases update 에는 --enable-pitr 와 --no-enable-pitr 둘뿐이고 보존 기간을 지정하는 인자가 없다. 켜면 7일 고정, 끄면 1시간이다. 「창을 줄여 비용을 아낀다」는 길은 없다. 그래서 판단은 7일 창이 가득 차는 날 같은 명령으로 다시 잰 값과, 끄면 잃는 복구 범위를 나란히 놓고 하기로 했다.

결과 — 지킨 복구 지점과 남은 비용 판단

정리


Share this post on:

Previous Post
dev 환경을 「쓸 때만 띄우는 구조」로 바꾸자는 안은 실측해 보니 끌 것이 없어 하지 않기로 했다
Next Post
130만 명에게 보낼 법정 통지 메일은 발송 시스템을 새로 짓지 않고 기존 큐에 채널 하나를 붙였다