문제 정의
코드는 다시 배포하면 되지만 데이터베이스 스키마 변경은 되돌리기가 어렵습니다. 컬럼을 삭제하거나 타입을 바꾸는 작업은 짧은 순간에도 운영 데이터를 잃게 만들 수 있고, 새 코드와 옛 코드가 동시에 떠 있는 배포 과정에서 예기치 않은 오류를 만들 수 있습니다.
마이그레이션은 개발 작업이 아니라 운영 위험을 다루는 작업입니다.
상황과 배경
작은 서비스에서는 마이그레이션을 코드 변경과 같은 커밋에 넣고 한 번에 배포하기 쉽습니다. 하지만 컨테이너가 순차적으로 뜨거나 배포가 중간에 실패하면 새 schema와 이전 코드가 만나는 시간이 생깁니다. 이때 읽기 호환성이 없으면 사용자는 500 오류를 보게 됩니다.
배포 직후 공개 경로를 확인하는 흐름은 배포 후 smoke test 체크리스트와 함께 운영해야 합니다.
마이그레이션을 안전하게 나누는 기준
- expand: 새 컬럼이나 테이블을 추가하되 기존 코드는 계속 동작하게 둡니다.
- dual write: 필요한 기간 동안 새 구조와 기존 구조에 함께 기록합니다.
- read switch: 새 구조를 읽도록 코드를 바꾸고 충분히 관찰합니다.
- contract: 더 이상 쓰지 않는 컬럼이나 경로는 마지막에 제거합니다.
실제 적용 방법
위험한 변경은 최소 두 번의 배포로 나눕니다. 예를 들어 필수 컬럼을 추가해야 한다면 먼저 nullable 컬럼을 추가하고, 백필을 수행한 뒤, 코드가 새 값을 쓰게 만들고, 마지막에 not null 제약을 적용합니다. 이 과정에서 백업과 복구 리허설은 선택이 아니라 기준입니다.
복구 기준은 작은 서비스에서 백업보다 복구 리허설이 먼저인 이유에서 더 자세히 다룹니다.
운영 체크리스트
- 마이그레이션 전 백업 위치와 복구 시간을 확인합니다.
- 이전 코드가 새 schema에서도 읽기 가능한지 확인합니다.
- 삭제, 타입 변경, not null 추가는 마지막 단계로 미룹니다.
- 대량 백필은 트래픽이 낮은 시간에 작은 배치로 실행합니다.
- 실패 시 롤백이 코드만으로 가능한지, DB 복구가 필요한지 구분합니다.
결론
DB 마이그레이션은 한 번에 끝내는 작업일수록 위험합니다. expand/contract로 나누고 롤백과 핫픽스 판단 기준까지 준비하면 작은 팀도 데이터 변경을 더 안정적으로 다룰 수 있습니다.