제가 만든 제로 다운타임 데이터베이스 마이그레이션 파이프라인 (PostgreSQL에서 Aurora로)

발행: (2025년 12월 4일 오후 12:22 GMT+9)
10 min read
원문: Dev.to

Source: Dev.to

문제

작년, 나는 자체 관리형 PostgreSQL에서 실행 중인 프로젝트를 인수하게 되었다. 데이터베이스는 500 GB까지 성장했고, 우리는 패치, 백업, 복제 문제 등 유지 보수에 너무 많은 시간을 소비하고 있었다. 관리형 운영, 더 나은 확장성, 그리고 AWS와의 네이티브 통합을 위해 Aurora PostgreSQL으로 이동하기로 결정했다.

하지만? 이 데이터베이스는 하루에 50,000명의 활성 사용자를 서비스하는 프로덕션 환경이었다. 다운타임이 발생하면 매출 손실과 고객 불만이 발생한다. 비즈니스에서는 0분이라는 유지 보수 윈도우를 제공했다. 압박감이 심했다.

처음 시도한 방법 (그리고 왜 실패했는가)

가장 먼저 생각한 것은 간단했다: 조용한 시간에 pg_dumppg_restore를 실행하는 것. 고전적인 접근법이죠?

# The naive approach
pg_dump -Fc production_db > backup.dump
pg_restore -d aurora_target backup.dump

500 GB 데이터베이스라면 네트워크와 인스턴스 규모에 따라 대략 4–6 시간이 걸렸다. 이는 사용자가 계속 쓰는 동안 소스에 4–6 시간 분량의 오래된 데이터가 누적된다는 뜻이다. 받아들일 수 없었다.

또한 PostgreSQL 고유의 논리 복제를 살펴보았지만, AWS 계정 간에 적절한 보안 제어를 갖춘 퍼블리케이션/서브스크립션을 설정하는 것이 거대한 작업이 되었다. 게다가 운영 툴링은 거의 DIY 수준이었다.

그때 AWS DMS를 발견했다. 전체 로드와 CDC(변경 데이터 캡처)를 관리형 서비스로 처리해준다. 문제는 이를 중심으로 마이그레이션을 반복 가능하고 안전하게 만드는 것이었다.

해결책

나는 네 가지 주요 구성 요소로 완전한 마이그레이션 프레임워크를 구축했다:

  • Terraform 모듈 – 모든 AWS 인프라스트럭처
  • Python 자동화 스크립트 – 검증 및 컷오버
  • GitHub Actions 워크플로 – CI/CD
  • CloudWatch 모니터링 – 전체 가시성

아키텍처 개요

Architecture Overview

블루‑그린 전략은 다음과 같이 동작한다: DMS가 기존 데이터를 전체 로드한 뒤 CDC 모드로 전환해 지속적인 변경을 캡처한다. 두 데이터베이스는 우리가 컷오버할 준비가 될 때까지 동기화된 상태를 유지한다.

Terraform 인프라스트럭처

재현성을 위해 모듈형 Terraform을 만들었다. DMS 모듈 예시는 다음과 같다:

module "dms" {
  source = "./modules/dms"

  project     = "db-migration"
  environment = "prod"

  subnet_ids         = var.private_subnet_ids
  security_group_ids = [module.networking.dms_security_group_id]

  replication_instance_class = "dms.r5.4xlarge"
  multi_az                   = true

  source_db_host     = var.source_db_host
  source_db_username = var.source_db_username
  source_db_password = var.source_db_password

  target_db_host     = module.aurora.cluster_endpoint
  target_db_username = var.aurora_master_username
  target_db_password = var.aurora_master_password
}

DMS 모듈이 생성하는 리소스:

  • 적절한 크기의 복제 인스턴스
  • SSL 구성이 적용된 소스 및 타깃 엔드포인트
  • CDC가 활성화된 복제 작업
  • 지연 및 오류 모니터링을 위한 CloudWatch 알람

검증 스크립트

컷오버 전에 데이터가 일치한다는 확신이 필요하다. 나는 여러 차원을 검사하는 Python 검증 도구를 작성했다:

# Quick validation (uses table statistics for fast estimates)
python validation.py --quick

# Full validation (exact counts, checksums, sequence values)
python validation.py --full

# Just check DMS status
python validation.py --dms

전체 검증이 수행하는 내용:

검사 항목설명
Row Counts소스와 타깃 간 정확한 행 수 비교
Checksums각 테이블 샘플 데이터의 MD5 해시
Sequences시퀀스 값이 동기화되었는지 확인
Primary Keys모든 테이블에 PK가 존재하는지 확인 (CDC에 필요)
DMS Status작업 실행 중, 복제 지연이 임계값 이하인지 확인

체크섬 검증 코드 스니펫:

def calculate_checksum(self, table: str, columns: list, limit: int = 1000) -> str:
    """Calculate MD5 checksum of sample rows."""
    cols = ", ".join(columns)
    query = f"""
        SELECT md5(string_agg(row_hash, '' ORDER BY row_hash))
        FROM (
            SELECT md5(ROW({cols})::text) as row_hash
            FROM {table}
            ORDER BY {columns[0]}
            LIMIT {limit}
        ) t
    """
    result = self.execute_query(query)
    return result[0][0] if result else None

컷오버 프로세스

컷오버는 가장 긴장되는 단계다. 나는 각 단계마다 자동 롤백 기능을 갖춘 다단계 프로세스를 구축했다:

단계작업롤백 가능 여부
1사전 검증 (DMS, 행 수 확인)가능
2동기화 대기 (CDC 지연이 임계값 이하)가능
3연결 차단 (소스 연결 종료)가능
4최종 동기화 (남은 변경 사항 대기)가능
5복제 중지수동만 가능
6사후 검증수동만 가능

컷오버 스크립트는 각 단계가 끝날 때마다 상태를 JSON에 저장하므로, 실패 시 재개가 가능하다:

# Always do a dry run first
python cutover.py --dry-run

# Execute when ready
python cutover.py --execute

# Resume from saved state if interrupted
python cutover.py --execute --resume

GitHub Actions 연동

모든 작업은 GitHub Actions를 통해 자동화된다. 프로덕션에서는 수동 승인이 필요하도록 컷오버 워크플로를 구성했다:

jobs:
  approval:
    name: Approve Cutover
    runs-on: ubuntu-latest
    if: github.event.inputs.mode == 'execute'
    environment: prod-cutover  # Requires manual approval
    steps:
      - name: Cutover Approved
        run: echo "Cutover approved"

  cutover:
    name: Database Cutover
    needs: [approval]
    # ... actual cutover steps

워크플로는 AWS Secrets Manager에서 자격 증명을 가져오고, 컷오버 스크립트를 실행하며, 감사용 상태 아티팩트를 업로드하고, 실패 시 SNS 알림을 전송한다.

결과

마이그레이션은 다음과 같은 지표와 함께 성공적으로 완료되었다:

지표
전체 마이그레이션 데이터 양512 GB
전체 로드 시간3 시간 22 분
컷오버 시 CDC 지연2.1 초
애플리케이션 다운타임0 초
데이터 검증 오류0

마이그레이션 후 관찰된 효과:

  • Aurora 리드 레플리카를 통한 읽기 지연 40 % 감소
  • 데이터베이스 유지 보수에 소요되는 시간 0 시간
  • 자동 백업 및 시점 복구 지원

교훈

  1. 검증 스크립트를 충분히 테스트하라. 처음에 체크섬 쿼리가 NULL 값을 제대로 처리하지 못하는 버그가 있었다. 다행히 스테이징에서 발견했다.
  2. DMS 인스턴스 크기를 적절히 잡아라. 처음엔 dms.r5.2xlarge를 사용했지만 전체 로드 중 CPU 한계에 걸렸다. 4xlarge로 업그레이드하니 마이그레이션 시간이 절반으로 줄었다.
  3. CDC 지연을 집요하게 모니터링하라. 지연이 30 초를 초과하면 알람이 울리도록 CloudWatch를 설정했다. 마이그레이션 중에 누군가 소스에서 배치 작업을 실행해 지연이 45 초로 급증했는데, 즉시 인지하고 지연이 안정될 때까지 컷오버를 미룰 수 있었다.
  4. 실제로 테스트한 롤백 계획을 마련하라. 컷오버 후 48 시간 동안 소스 PostgreSQL을 그대로 운영했다. 마이그레이션과 무관한 사소한 버그가 발생했을 때 롤백 옵션이 있어 모두가 안심하고 문제를 조사할 수 있었다.
  5. 필요하다고 생각하는 것보다 더 많이 소통하라. 우리는 매시간 업데이트를 전송했다.
Back to Blog

관련 글

더 보기 »