MMeshOps
데이터베이스 마이그레이션 실전: 다운타임 없는 안전한 DB 변경
10예상 10중급

컬럼 이름을 그냥 바꾸면 터집니다: 안전한 우회로

ALTER TABLE로 컬럼 이름을 한 번에 바꿨을 때 왜 서버 전체에 에러가 발생하는지 구조적인 이유를 분석합니다.

운영 중인 데이터베이스에서 컬럼 이름을 변경해야 하는 상황은 흔하게 발생합니다. 기획이 변경되었거나, 초기에 지은 이름이 더 이상 적절하지 않을 때 우리는 무심코 `ALTER TABLE RENAME COLUMN` 명령어를 떠올립니다. 하지만 트래픽이 발생하고 있는 운영 서버에서 이 명령어를 바로 실행하면, 곧바로 서비스 장애(다운타임)로 이어질 수 있습니다. 이번 시간에는 왜 단순한 이름 변경이 시스템 전체를 마비시키는지 구조적인 원인을 알아보고, 이를 해결하기 위한 '안전한 우회로'의 개념을 소개합니다.

컬럼명 변경이 불러오는 참사

개발 환경에서는 테이블의 컬럼 이름을 바꾸는 것이 아주 간단합니다. 데이터베이스 클라이언트 도구를 열어서 이름을 수정하거나, 간단한 SQL 스크립트 한 줄만 실행하면 끝납니다. 하지만 사용자가 끊임없이 접속하고 있는 운영 환경(Production)에서는 이야기가 완전히 다릅니다.

데이터베이스의 스키마를 변경하는 행위는 본질적으로 애플리케이션 코드와의 강한 결합을 전제로 합니다. 만약 우리가 `users` 테이블의 `phone_number` 컬럼을 `contact_number`로 변경한다고 가정해 보겠습니다. 데이터베이스에서 이 컬럼의 이름이 바뀌는 순간, 기존에 `phone_number`를 참조하고 있던 애플리케이션의 모든 쿼리는 즉시 실패하게 됩니다.

애플리케이션과 DB의 타이밍 불일치

장애의 근본적인 원인은 애플리케이션 배포와 데이터베이스 마이그레이션이 완벽하게 동시에 이루어질 수 없다는 점에 있습니다.

우리는 보통 코드를 수정하여 새로운 버전의 애플리케이션을 만들고, 이를 서버에 배포합니다. 그리고 데이터베이스 마이그레이션 스크립트를 실행하여 스키마를 업데이트합니다. 이 두 가지 작업 중 어느 것을 먼저 하더라도 불일치(Mismatch)가 발생하는 시간적 간극이 존재합니다.

  1. DB를 먼저 변경할 경우: 데이터베이스에는 이미 `contact_number`로 이름이 바뀌었지만, 아직 배포되지 않은 구버전 애플리케이션은 여전히 `phone_number`를 찾습니다. 결과적으로 데이터를 읽거나 쓰는 모든 요청에서 "Unknown column 'phone_number'"라는 에러가 쏟아집니다.
  2. 앱 코드를 먼저 배포할 경우: 신버전 애플리케이션은 `contact_number` 컬럼을 찾지만, 데이터베이스는 아직 마이그레이션이 실행되지 않아 `phone_number`만 가지고 있습니다. 역시 에러가 발생합니다.

배포 순서에 따른 장애 원인

DB 마이그레이션 선행

구버전 앱이 존재하지 않는 옛날 컬럼명을 참조하여 쿼리 에러 발생

애플리케이션 배포 선행

신버전 앱이 아직 생성되지 않은 새 컬럼명을 참조하여 쿼리 에러 발생

이처럼 짧은 시간이지만 두 시스템 간의 상태가 어긋나는 구간을 방치하면 서비스는 중단됩니다. 이를 우리는 다운타임(Downtime)이라고 부릅니다.

무중단 배포 환경에서의 한계

현대의 웹 서비스들은 대부분 서버를 여러 대 운영하며, 사용자 경험을 해치지 않기 위해 롤링 배포(Rolling Update)나 블루-그린(Blue-Green) 배포와 같은 무중단 배포 방식을 사용합니다.

무중단 배포의 핵심은 배포가 진행되는 동안 구버전 애플리케이션과 신버전 애플리케이션이 동시에 실행된다는 점입니다. 일부 서버는 옛날 코드로 돌아가고 있고, 일부 서버는 방금 배포된 새로운 코드로 돌아가고 있습니다.

파괴적 변경(Destructive Change)의 위험성

이러한 환경에서 `RENAME COLUMN`이나 `DROP COLUMN` 같은 파괴적인 스키마 변경은 치명적입니다. 파괴적 변경이란 기존 데이터 구조를 수정하거나 삭제하여 이전 상태와의 호환성을 깨뜨리는 작업을 말합니다.

구버전 앱과 신버전 앱이 공존하는 상황에서 데이터베이스 스키마를 단숨에 변경해 버리면, 반드시 둘 중 하나의 버전은 오작동을 일으킬 수밖에 없습니다.

컬럼명 변경 시 흔한 착각

오해 또는 실수

새벽 시간에 배포하면 RENAME을 써도 문제없을 것이다.

바로잡기

글로벌 서비스이거나 새벽에도 트래픽이 있다면 단 몇 초의 다운타임도 결제 실패 등 치명적인 장애를 유발합니다.

오해 또는 실수

앱과 DB 배포 자동화를 잘 구축하면 간극을 0초로 만들 수 있다.

바로잡기

물리적으로 앱 서버 전체가 갱신되는 데는 시간이 걸리며, DB 변경이 0초 만에 모든 서버에 반영되는 것은 불가능합니다.

안전한 우회로: Expand and Contract 패턴

그렇다면 다운타임 없이 컬럼 이름을 바꾸거나 데이터 구조를 변경하려면 어떻게 해야 할까요? 핵심은 한 번에 변경하려는 욕심을 버리고, 여러 단계로 쪼개어 접근하는 것입니다.

이때 사용되는 대표적인 전략이 바로 팽창과 수축(Expand and Contract) 패턴입니다. 이 패턴은 기존 애플리케이션과의 하위 호환성(Backward Compatibility)을 철저히 유지하면서 점진적으로 스키마를 변경하는 기법입니다.

패턴의 핵심 원리

Expand and Contract 패턴은 이름 그대로 데이터베이스의 구조를 먼저 '팽창'시킨 다음, 모든 준비가 끝나면 다시 불필요한 부분을 '수축'시키는 방식입니다.

  1. 팽창 (Expand): 기존 컬럼을 놔둔 채로, 새로운 이름의 컬럼을 추가합니다. 이렇게 하면 구버전 애플리케이션은 기존 컬럼을 계속 사용할 수 있으므로 아무런 에러가 발생하지 않습니다.
  2. 이전 및 전환: 백그라운드에서 데이터를 복사하고, 애플리케이션이 새로운 컬럼을 사용하도록 코드를 점진적으로 수정하여 배포합니다.
  3. 수축 (Contract): 모든 애플리케이션이 새로운 컬럼만 완벽하게 사용하고 있음이 확인되면, 비로소 예전 컬럼을 삭제하여 데이터베이스 구조를 정리합니다.

파괴적 변경 vs 점진적 변경

비교 항목파괴적 변경 (RENAME)점진적 변경 (Expand/Contract)
작업 방식한 번의 쿼리로 직접 변경여러 단계와 배포를 거쳐 점진적 전환
장애 발생 확률매우 높음 (필연적 다운타임)매우 낮음 (무중단 가능)
구버전 앱 호환성호환되지 않음완벽히 호환됨
소요 시간 및 비용짧지만 리스크 큼길고 복잡하지만 안전함

왜 우회로를 선택해야 하는가?

물론 `RENAME COLUMN` 명령어 한 줄이면 끝날 일을 여러 단계의 마이그레이션 파일과 애플리케이션 배포로 쪼개는 것은 번거롭게 느껴질 수 있습니다. 개발자 입장에서는 코드를 여러 번 수정하고 PR(Pull Request)을 올려야 하는 귀찮은 작업입니다.

하지만 운영 안정성 측면에서 보면 이 우회로는 필수적입니다. 수백, 수천 명의 사용자가 서비스를 이용하고 있는 상황에서 에러 발생 확률을 0%에 가깝게 통제하는 것은 실무 소프트웨어 엔지니어링의 기본 소양이기 때문입니다.

실생활 비유: 다리 공사

출퇴근 차량이 쏟아지는 핵심 교량의 차선을 넓힌다고 상상해 보세요. 기존 다리를 갑자기 부수고(`DROP`) 새 다리를 지으면 그동안 교통은 완전히 마비됩니다(`다운타임`).

대신, 옆에 임시 교량이나 새로운 다리를 먼저 건설(`Expand`)하고, 차량들이 서서히 새 다리로 우회하도록 안내(`전환`)한 뒤, 통행량이 0이 되었을 때 기존 다리를 철거(`Contract`)하는 방식이 바로 무중단 마이그레이션의 핵심입니다.

다음 단계로의 준비

이제 우리는 파괴적인 스키마 변경이 왜 위험한지, 그리고 왜 여러 단계를 거치는 점진적 접근 방식이 필요한지 구조적인 이유를 명확히 이해했습니다. 다운타임을 피하기 위해서는 데이터베이스가 항상 현재 실행 중인 모든 버전의 애플리케이션 코드와 동시에 호환되어야 한다는 점이 가장 중요합니다.

다음 회차부터는 이 Expand and Contract 패턴을 구체적으로 어떻게 실무에 적용하는지, 무중단 스키마 변경 5단계 전략을 하나씩 상세하게 파헤쳐 보겠습니다. 첫 번째 단계인 새로운 컬럼의 추가와 기존 데이터의 안전한 이전에 대해 다룰 예정이니 기대해 주세요.

개념 퀴즈

퀴즈 답을 맞춰야 학습 완료가 됩니다.

운영 중인 서비스에서 ALTER TABLE RENAME COLUMN 명령어를 실행했을 때 서비스 장애가 발생하는 가장 근본적인 이유는 무엇인가요?

3줄 요약

  1. 1운영 환경에서 RENAME이나 DROP 같은 파괴적인 스키마 변경은 즉각적인 서비스 장애(다운타임)를 유발합니다.
  2. 2장애의 근본 원인은 애플리케이션 배포 시점과 데이터베이스 마이그레이션 실행 시점 사이의 타이밍 불일치에 있습니다.
  3. 3이를 해결하기 위해 하위 호환성을 유지하며 스키마를 점진적으로 변경하는 Expand and Contract(팽창과 수축) 패턴을 사용해야 합니다.