무중단 스키마 마이그레이션 설계 가이드
무중단 스키마 마이그레이션의 핵심은 확장, 이행, 정리 세 단계를 분리하는 것입니다.
스키마 변경이 위험한 이유
문제는 DDL 자체보다 애플리케이션과 데이터가 서로 다른 속도로 움직인다는 점입니다.
- 애플리케이션 서버는 점진적으로 교체됩니다.
- 배치 작업은 구버전 로직을 한동안 유지할 수 있습니다.
- 읽기 전용 리포트나 외부 시스템은 이전 컬럼을 참조할 수 있습니다.
- 롤백이 필요하면 구버전 코드가 다시 살아날 수 있습니다.
즉 새 스키마를 추가하는 순간, 한동안은 구버전과 신버전이 함께 존재하는 세계를 견뎌야 합니다.
가장 안전한 패턴은 Expand -> Migrate -> Contract
무중단 변경은 보통 다음 순서를 따릅니다.
1. Expand : 새 컬럼/테이블/인덱스를 추가한다.
2. Migrate : 애플리케이션과 데이터 흐름을 점진적으로 옮긴다.
3. Contract : 더 이상 쓰지 않는 구조를 제거한다.
예를 들어 full_name 컬럼을 first_name, last_name으로 분리한다고 해봅시다.
- 새 컬럼 두 개를 추가한다.
- 애플리케이션은 한동안 두 형태를 모두 읽고 쓴다.
- 백필 작업으로 기존 데이터를 옮긴다.
- 신버전 배포가 완전히 자리 잡으면 구컬럼을 제거한다.
이 순서를 지키지 않고 컬럼 삭제부터 들어가면, 아직 살아 있는 구버전 코드가 즉시 장애를 일으킵니다.
호환 기간을 명시적으로 설계해야 한다
마이그레이션에서 가장 중요한 것은 호환 기간입니다. 다음 질문에 답할 수 있어야 합니다.
- 구버전 코드가 몇 시간 또는 며칠 동안 살아 있어도 괜찮은가
- 이중 쓰기 기간 동안 데이터 충돌은 어떻게 다루는가
- 읽기 경로는 어느 시점에 완전히 전환하는가
- 백필 실패 시 재시도와 검증은 어떻게 하는가
실무에서는 읽기와 쓰기를 분리해서 전환하는 경우가 많습니다. 먼저 쓰기를 이중화하고, 충분히 데이터가 채워진 뒤 읽기 경로를 바꾸는 방식이 안전합니다.
백필은 배치 한 번으로 끝나는 일이 아니다
대용량 테이블을 다룰 때 백필은 트래픽과 경쟁합니다. 이때 흔한 실수는 오프피크 시간에 한 번 돌리고 끝낼 수 있다고 믿는 것입니다. 실제로는 다음 요소가 중요합니다.
- 배치 크기를 작게 유지할 것
- 잠금과 인덱스 부하를 관측할 것
- 재실행 가능한 형태로 만들 것
- 어느 구간까지 성공했는지 체크포인트를 남길 것
백필 작업도 애플리케이션 기능처럼 관측 가능해야 합니다. 처리량, 실패율, 남은 레코드 수를 지표로 두지 않으면 운영자가 불안한 감으로만 판단하게 됩니다.
롤백은 스키마가 아니라 단계별 상태를 기준으로 본다
무중단 마이그레이션에서 롤백은 “DDL을 되돌린다”보다 “이전 읽기/쓰기 경로로 되돌릴 수 있는가”가 중요합니다.
- 새 컬럼 추가 단계는 대체로 롤백 부담이 작습니다.
- 읽기 경로 전환 이후는 애플리케이션 롤백이 더 중요합니다.
- 구컬럼 삭제 이후는 사실상 완전 롤백이 어려울 수 있습니다.
그래서 삭제 단계는 항상 가장 마지막에 와야 하고, 충분한 관찰 기간이 지나기 전에는 정리 작업을 서두르지 않는 편이 좋습니다.
실무에서 자주 터지는 문제
- 애플리케이션은 이중 쓰기를 시작했지만 배치는 구컬럼만 읽음
- 새 인덱스를 추가했지만 쿼리 플랜 변화는 검증하지 않음
- 백필 중 트랜잭션을 너무 크게 잡아 복제 지연이 발생
- 삭제 전 사용처 조사를 코드 검색만으로 끝냄
특히 외부 BI, 데이터 파이프라인, 임시 운영 스크립트는 애플리케이션 코드보다 늦게 발견되는 경우가 많습니다. 삭제 단계 전에 실제 접근 로그와 쿼리 패턴을 확인하는 것이 안전합니다.
체크리스트
- 새 스키마가 구버전 코드와 공존 가능한가
- 읽기와 쓰기 전환 단계를 분리했는가
- 백필 작업이 재시도 가능하고 관측 가능한가
- 정리 단계 전에 모든 사용처를 로그와 쿼리 기준으로 검증했는가
- 삭제 전 충분한 관찰 기간을 두었는가
마무리
무중단 스키마 마이그레이션은 SQL 문법보다 전환 설계가 더 중요합니다. 성공적인 팀은 컬럼 추가보다 호환 기간을 먼저 생각하고, 배치보다 관측을 먼저 준비하며, 정리보다 안정화 기간을 더 길게 둡니다. 데이터 변경은 결국 코드 변경이 아니라 시스템 진화 전략입니다.
Continue Reading
다음으로 읽기 좋은 글
데이터베이스 스키마 Expand-Contract 적용 가이드
스키마 변경을 한 번에 끝내려 하면 배포 위험이 커집니다. Expand-Contract 패턴은 변경을 안전한 단계로 쪼개는 실전 방법입니다.
🗄️ DatabaseIdempotent Backfill 체크포인트 설계
백필은 한 번에 끝나지 않는 경우가 많습니다. 중단과 재시작을 견디는 체크포인트 설계가 데이터 작업의 안정성을 좌우합니다.
📈 최신 동향PostgreSQL 18 최신 동향: 실무에서 진짜 중요한 변화
PostgreSQL 18은 단순 업그레이드 뉴스가 아닙니다. AIO, skip scan, 업그레이드 후 성능 회복, OAuth, generated columns까지 운영팀과 개발팀 모두에게 영향이 큰 변화가 들어왔습니다.
💬 Language런타임 스키마 경계 실전 설계
TypeScript, Python, Java 같은 언어에서 정적 타입만으로 막기 어려운 외부 입력을 런타임 스키마로 보호하는 방법을 정리합니다.
다음 탐색