무중단 마이그레이션
개요
롤링 배포 중에도 실행 중인 시스템을 정상 상태로 유지하는 스키마 변경 규율입니다. 롤아웃 과정에서 기존 파드와 새 파드는 하나의 데이터베이스를 공유하므로, 스키마는 두 앱 버전과 동시에 호환되어야 합니다. 파괴적인 마이그레이션(migration)을 해당 배포와 함께 수행하는 것이 전형적인 자초한 장애 원인입니다.
작성 규칙 (모든 프로젝트)
- 두 종류의 마이그레이션을 명확히 구분: 멱등성을 가진
current/세트(개발 반복 — 매 사이클마다 재실행,CREATE OR REPLACE/IF NOT EXISTS사용, 객체는 최종 형태로, 생성 후ALTER없음)와 커밋된 마이그레이션(불변, 순서 있음, 실제로 배포되는 것).ALTER DEFAULT PRIVILEGES만 유일하게 허용된 인라인ALTER입니다. - 소유권(ownership) 은 마이그레이션이 실행되는 방식에서 비롯되며,
ALTER ... OWNER를 흩뿌리지 않습니다. - 단일 부트스트랩 진실 공급원 — 로컬/Docker 초기화 경로와 섀도우/테스트 DB가 동일한 진실 공급원을 공유합니다. 모든 환경이 동일하게 구축됩니다.
확장/축소 (병렬 변경)
적용 대상: 데이터베이스에 배포 시 유지되어야 할 데이터가 있는 경우(데이터가 있는 스테이징, 프로덕션). 면제: 로컬/초기화 친화적인 프로젝트 — 하지만 커밋된 마이그레이션은 이 규칙이 적용된다고 가정하고 작성하십시오. 그래야 프로모션 시 재작성이 필요 없습니다.
스키마 변경은 한 번에 하나가 아닌 세 개의 릴리스에 걸쳐 나누어 수행합니다.
- 확장(Expand) — 새로운 구조를 추가적으로, 이전 버전과 호환되게 추가합니다: 새로운 nullable 컬럼, 새로운 테이블, 새로운 함수. 앱 버전 N은 변경 없이 계속 실행됩니다.
- 마이그레이션(Migrate) — 제한된 배치(batch) 로 백필합니다(절대 테이블을 잠그는 단일
UPDATE사용 금지). 필요 시 앱 N+1에서 듀얼 라이트(dual-write)를 수행하고, 읽기를 새 구조로 전환합니다. 지금NOT NULL을 추가합니다(제약 조건을NOT VALID로 추가한 후,VALIDATE를 별도로 수행). - 축소(Contract) — 앱 N이 완전히 제거된 후에야 이후 릴리스에서 이전 컬럼/제약 조건을 제거합니다.
PostgreSQL 주의사항
| 주의사항 | 안전한 접근 방식 |
|---|---|
변동성이 크거나 대규모 백필 기본값을 가진 NOT NULL 컬럼 | Nullable로 추가 → 배치 단위로 백필 → 제약 조건을 NOT VALID로 추가 → VALIDATE |
| 제약 조건 추가 | 먼저 NOT VALID로 추가한 후 VALIDATE CONSTRAINT 실행 (약한 락) |
| 인덱스 구축 | CREATE INDEX CONCURRENTLY — 트랜잭션 내에서 실행 불가; 마이그레이션 도구의 트랜잭션 래핑과 분리하여 실행 |
| 프로덕션을 멈추게 하는 차단된 마이그레이션 | lock_timeout/statement_timeout 설정으로 빠르게 실패 처리 |
| 컬럼 이름 변경 | 확장/축소 적용: 새 컬럼 추가 → 백필 → 읽기 전환 → 이전 컬럼 제거 (릴리스 분리) |
프로덕션에서 "최종 형태 CREATE OR REPLACE"만으로 충분하지 않은 이유
그 규칙은 개발자 편의성을 위한 것이며 개발 환경에서는 올바릅니다. 그러나 실시간 사용자가 있는 프로덕션과 롤링 배포 환경에서는 두 앱 버전이 롤아웃 기간 동안 스키마를 공유합니다. 따라서 확장/축소가 변경을 안전하게 만드는 방법입니다. 이 둘을 혼동하지 마십시오.
전체 근거: 헌법 제17조, engineering-constitution/references/engineering-constitution.md에 번들로 포함되어 있습니다. 배포 파이프라인: cloud-delivery-aks.