TechFeedTechFeed
Backend

무중단 DB 스키마 마이그레이션 체크리스트 2026 | expand-contract·백필·롤백

무중단 데이터베이스 스키마 마이그레이션 체크리스트. 확장-축소(expand-contract), 백필·이중 쓰기, 위험 DDL 표, 인덱스·락·타임아웃, N-1 앱 호환, 롤백 구간, Flyway·Prisma·golang-migrate 선택, PostgreSQL ALTER·CREATE INDEX 참고와 백엔드·API·데브옵스 배포 전 점검 항목을 정리한다.

by

컬럼 이름 하나 바꾸고 배포했는데 5분간 락이 걸린 적이 있다면, “마이그레이션 = SQL 한 방”이 이미 깨진 겁니다. 무중단 스키마 변경은 앱 코드와 DB 변경을 같은 배포 단위로 묶지 않는 일부터 시작합니다. 확장(expand) → 이중 쓰기·읽기 → 축소(contract) 순서를 지키면, 트래픽이 있는 서비스에서도 롤백 창을 남길 수 있습니다.


아래는 백엔드·데브옵스·풀스택이 PR 전에 그대로 붙일 수 있는 점검 목록입니다. 배포 공통 게이트는 프로덕션 배포 체크리스트를, 단계 공개가 필요하면 기능 플래그 롤아웃을 같이 보세요.


무중단이 필요한 때 | 점검 창으로 충분한 때

모든 ALTER를 무중단으로 가져가면 비용이 커집니다. 먼저 표로 갈라 두고, 팀에 “이 변경은 어느 줄인가”만 합의해도 야간 장애가 줄어듭니다.


상황권장이유
24/7 API·결제·로그인 트래픽무중단(확장-축소)짧은 락도 타임아웃·재시도 폭주로 이어짐
내부 배치·야간 전용 잡점검 창 가능사용자 영향 적으면 단순 마이그레이션이 안전
테이블 수억 행·핫 파티션무중단 + 온라인 도구풀 테이블 리라이트가 수분~수시간 가능
개발/스테이징 전용 DB단순 적용속도·가독성 우선, 패턴 연습용
파괴적 데이터 삭제·PII 정리별도 런북스키마 이슈가 아니라 데이터 수명 이슈

마틴 파울러의 진화형 데이터베이스 설계(Evolutionary Database Design)는 “스키마와 코드를 작은 단위로, 항상 호환 가능하게” 맞추라고 말합니다. 한 스프린트에 rename·타입 변경·NOT NULL·인덱스 재작성을 한꺼번에 넣으면 롤백이 거의 불가능해집니다.


빠른 판정 — “지금 떠 있는 구 버전 앱이 이 스키마를 읽을 수 있나?”에 아니요면 배포 순서가 틀린 겁니다. 먼저 스키마를 넓히고, 앱을 올리고, 나중에 좁힙니다.


확장-축소 3단계 | 한 배포에 한 방향만

무중단의 뼈대는 단순합니다. 넓히기 → 옮기기 → 좁히기. 각 단계는 별도 마이그레이션 파일·별도 배포로 나눕니다.


예: user_namedisplay_name 이름 변경. 잘못된 한 방: RENAME COLUMN 직후 앱 배포. 맞는 순서: (1) display_name 추가(nullable) (2) 앱이 둘 다 쓰기·우선 읽기 (3) 백필 완료 검증 (4) 앱은 display_name만 (5) 구 컬럼 삭제. 중간에 어디든 멈추면 서비스는 계속 돕니다.


데이터베이스 스키마 마이그레이션과 서버 배포 파이프라인을 나타내는 개발 환경
스키마 확장과 앱 배포를 분리하면 구 버전 인스턴스와 신 스키마가 잠시 공존해도 안전하다

실행 전 체크리스트 | 백업·락·용량·권한

SQL이 맞아도 디스크·권한·락 큐가 막히면 장애입니다. 스테이징에서 “같은 데이터 규모 근사치”로 한 번 돌린 기록이 없으면 프로덕션 금지에 가깝습니다.


스테이징 함정 — 스테이징 1만 행에서 0.2초였던 ALTER가 프로덕션 2억 행에서 40분이 되는 경우가 흔합니다. 행 수·인덱스·동시 쓰기 QPS를 적고, 가능하면 프로덕션 스냅샷 복제본에서 dry-run 하세요.


위험 연산 표 | rename·타입·NOT NULL·DROP

ORM이 생성한 한 줄이 실제로는 테이블 재작성을 유발할 수 있습니다. PostgreSQL·MySQL 버전별로 다릅니다. “문서에 쓰인 빠른 경로”를 버전 단위로 확인하세요.


연산흔한 사고안전한 패턴
컬럼 RENAME구 앱이 컬럼 못 찾음새 컬럼 추가 → 이중 쓰기 → 구 제거
타입 변경 (int→bigint 등)리라이트·검증 실패새 컬럼 + 백필 + 전환. 가능하면 호환 타입만
NOT NULL 추가기존 NULL 행·긴 검증DEFAULT/백필 완료 후 제약. 검증을 배치로
DEFAULT 변경버전별 메타만/전체 갱신 차이엔진 문서 확인. 대량 갱신이면 배치
인덱스 CREATE쓰기 블로킹CONCURRENTLY·온라인 DDL·유지보수 창
FK 추가검증 스캔·부모 락데이터 정리 후 NOT VALID → VALIDATE 분리(지원 시)
DROP COLUMN/TABLE구 코드 500·복구 불가코드 제거 배포 후, 관찰 기간 지나 삭제

백필·이중 쓰기 체크리스트

스키마만 넓히고 데이터를 안 채우면 신 코드가 빈 값을 봅니다. 백필은 “한 번에 UPDATE 전체”가 아니라 배치·재개 가능·관측 가능이어야 합니다.


배치 데이터 이관과 모니터링 대시보드를 연상하는 서버 인프라
백필은 재개 가능한 배치와 불일치 알람이 있어야 무중단 전환이 성립한다

앱 호환 체크리스트 | N과 N-1이 동시에 산다

카나리 10%면 90%는 아직 구 바이너리입니다. 스키마가 구 코드를 깨는 순간, 그 90%가 에러 예산입니다.


인덱스·락·타임아웃 운영 체크

인덱스 하나가 쓰기 경로를 멈출 수 있습니다. PostgreSQL의 CREATE INDEX CONCURRENTLY는 트랜잭션 블록 밖에서 돌고, 실패 시 invalid 인덱스가 남을 수 있습니다. MySQL·MariaDB는 online DDL·알고리즘 옵션을 버전별로 확인합니다.


롤백·장애 시 체크리스트

축소(contract) 이후 DROP은 사실상 앞으로만 갑니다. 롤백 가능 구간을 배포 노트에 적지 않으면, 장애 때 회의만 늘어납니다.


장애 대응과 롤백을 위한 운영 체크리스트 개념 이미지
축소 단계 전후로 롤백 가능 구간이 달라진다. 배포 노트에 구간을 명시한다

도구 짧은 표 | Flyway·Liquibase·Prisma·golang-migrate

도구는 파일 버전 관리·적용 이력·CI 연동을 대신해 줍니다. 무중단 패턴 자체는 도구가 자동으로 해주지 않습니다.


도구잘 맞는 경우주의
Flyway / LiquibaseSQL 중심·다수 서비스 표준화팀 규약 없으면 거대 스크립트화
golang-migrate 등 CLI앱과 같은 저장소, 단순 up/downdown이 프로덕션에서 위험한 경우 비활성
Prisma Migrate 등 ORM타입·스키마 동기화자동 diff를 무중단 단위로 쪼개야 함
gh-ost / pt-osc 등MySQL 대용량 온라인 변경운영 러닝커브·컷오버 리허설 필요

의존성 봇이 ORM 메이저 업을 올리면 마이그레이션 동작이 바뀔 수 있습니다. 대규모 흡수 주는 의존성 업데이트 체크리스트와 DDL 주를 겹치지 마세요.


한 장 플로 | PR부터 축소까지

  1. 분류 — 표에서 무중단 vs 점검 창. 위험 연산이면 확장-축소 강제.
  2. Expand PR — 추가만. 롤백 노트·예상 락·스테이징 dry-run 결과 첨부.
  3. 앱 호환 배포 — 구·신 스키마 모두 동작. 필요 시 플래그 기본 off.
  4. 백필 — 배치·재개·diff 알람. 완료 정의 충족 시까지 축소 금지.
  5. 읽기/쓰기 전환 — 신 경로 비율 승급. 에러·지연 가드레일.
  6. Contract PR — 구 코드 제거 배포 후, 관찰 기간 지나 컬럼/테이블 삭제.
  7. 회고 한 줄 — 예상 밖 락·diff·타임아웃을 체크리스트에 환원.

결제·권한처럼 잘못되면 돈이 움직이는 스키마는 단계를 더 쪼개고, 리뷰어를 두 명 두는 편이 낫습니다. “금요일 오후 Expand+Contract 한 방”은 체크리스트 통과로 보지 마세요.


참고 자료


관련 내부 글: 프로덕션 배포 체크리스트 · 기능 플래그 롤아웃 · 구조화 로깅 · 시크릿·환경변수 · Sentry 모니터링 · 회로 차단기 사례


자주 묻는 질문

점검 창 10분이면 무중단 패턴이 필요 없나요?

트래픽이 없고 롤백이 단순하면 점검 창이 더 안전할 수 있습니다. 다만 창이 “항상 10분”이 아니고, 테이블이 커질수록 창이 길어집니다. 성장 중인 서비스는 지금 단순 적용이 되더라도, rename·NOT NULL 같은 연산부터 확장-축소 습관을 들이는 편이 이후 비용이 작습니다.


Prisma나 ORM 자동 마이그레이션만으로 충분한가요?

이력 관리·로컬 동기화에는 충분합니다. 프로덕션 무중단은 자동 diff를 사람이 쪼개고, 백필·이중 쓰기·관찰을 추가해야 합니다. 자동 생성 SQL에 RENAME·DROP이 있으면 그대로 머지하지 마세요.


down 마이그레이션을 프로덕션에서 실행해도 되나요?

데이터 손실·재작성 위험이 있으면 비추천입니다. 많은 팀이 프로덕션 down을 막고, 앞으로 가는 보정 마이그레이션(forward fix)만 허용합니다. down이 필요하다면 스테이징 복원 드릴과 동일한 등급의 리뷰를 요구하세요.


컬럼 추가만 하는데도 락이 걸리나요?

엔진·버전·기본값·NOT NULL 여부에 따라 다릅니다. “빠른 메타데이터만 바꾸는 경로”와 “테이블 재작성”이 갈립니다. 사용 중인 DB 메이저 버전 문서를 보고, 스테이징에서 락 대기 시간을 재는 것이 안전합니다.


백필이 며칠 걸리는데 배포를 멈춰야 하나요?

Expand와 호환 앱은 먼저 배포한 뒤, 백필만 길게 돌리면 됩니다. 그 기간 동안 이중 쓰기·불일치 알람이 동작해야 합니다. 백필 중에 Contract(삭제)만 하지 않으면 서비스는 계속 배포할 수 있습니다.


멀티 테넌트·샤딩이면 순서가 달라지나요?

샤드마다 적용 시각이 어긋날 수 있어, 앱은 더 오래 “구·신 스키마 모두” 지원해야 합니다. 테넌트 단위 카나리, 샤드 버전 표, 실패 샤드만 재시도하는 런북을 추가하세요. 전 샤드 일괄 Contract는 마지막에 둡니다.


데이터베이스마이그레이션백엔드PostgreSQL스키마배포API데브옵스개발자ORM체크리스트

함께 보면 좋은 문제 해결

EXPLORE / Backend

이어서 읽어보기

전체 토픽 둘러보기