← 전체 글로 돌아가기

DB

PostgreSQL 마이그레이션을 되돌릴 때 데이터까지 복구된다고 착각한 실수 정리

스키마 롤백과 데이터 복구를 같은 것으로 취급했던 배포 실수에서 안전한 순서를 정리했다.

롤백 버튼을 눌렀는데 행은 돌아오지 않았다

컬럼 이름을 바꾸는 마이그레이션을 배포한 뒤 애플리케이션 오류가 발생했다. 마이그레이션 도구의 down 명령을 실행하면 이전 상태가 될 것이라 생각했지만, 이미 변환하거나 삭제한 데이터는 복원되지 않았다. 스키마의 모양과 데이터의 과거 시점은 서로 다른 문제였다.

실수한 작업은 ALTER TABLE만 되돌리면 충분하다고 본 것이었다. 실제로는 배포 전 백업과 복구 시점을 확인하지 않았고, 애플리케이션이 새 컬럼과 옛 컬럼을 동시에 이해하도록 만드는 단계도 생략했다.

되돌릴 수 있는 변경으로 쪼개기

다음부터는 컬럼을 바로 rename하지 않고 호환 기간을 둔다.

ALTER TABLE users ADD COLUMN display_name text;

UPDATE users
SET display_name = name
WHERE display_name IS NULL;

애플리케이션은 한동안 display_name을 우선 읽되 name도 쓸 수 있게 하고, 백필 결과를 검증한다. 새 코드가 안정된 뒤 쓰기를 두 컬럼에 맞추고, 마지막에 옛 컬럼 제거를 별도 배포로 분리한다. 각 단계 사이에는 문제가 생겼을 때 코드만 되돌릴 수 있는 시간이 생긴다.

배포 전에는 다음처럼 현재 상태를 남겼다.

pg_dump --format=custom --file=before-release.dump "$DATABASE_URL"
psql "$DATABASE_URL" -c "select count(*) from users where name is null;"

운영 데이터에서 복구 테스트를 할 때는 원본 데이터베이스에 바로 덮어쓰지 않고 별도 인스턴스에 복원한다. down 명령은 스키마 변경의 역연산일 뿐, 백업 없이는 삭제 데이터의 타임머신이 아니다.

배포 전후에 묻는 질문

  • 이 변경은 이전 애플리케이션 버전도 읽을 수 있는가?
  • 삭제나 변환되는 값의 백업 위치와 보존 기간을 확인했는가?
  • 백업 파일을 실제 별도 데이터베이스에 복원해 보았는가?
  • 백필 건수와 null 건수를 기록했는가?
  • 스키마 롤백과 데이터 복구 절차를 서로 다른 문서로 적었는가?

그날의 문제는 명령어 하나를 몰라서가 아니라 롤백이라는 말을 너무 넓게 쓴 데서 시작됐다. 지금은 마이그레이션 PR에 ‘코드 롤백’, ‘스키마 역연산’, ‘데이터 복구’ 세 항목을 따로 적고 승인받는다.