대규모 데이터베이스 온라인 스키마 변경 전략: 무중단 DDL과 롤백 계획 수립 가이드

서비스가 운영 중인 데이터베이스에서 테이블 구조를 변경하는 작업은 단순히 DDL 문장을 실행하는 것으로 끝나지 않는다. 데이터가 수천만 건 이상 쌓인 테이블에 컬럼을 추가하거나 인덱스를 생성하면 테이블 잠금, 트랜잭션 지연, 복제 지연, 스토리지 사용량 증가와 같은 문제가 동시에 발생할 수 있다. 특히 주문, 결제, 인증처럼 중단을 허용하기 어려운 시스템에서는 짧은 잠금도 전체 서비스 장애로 이어질 수 있다.
온라인 스키마 변경의 핵심은 DDL을 무조건 빠르게 실행하는 것이 아니라 애플리케이션과 데이터베이스가 이전 구조와 새로운 구조를 일정 기간 함께 사용할 수 있도록 전환 과정을 설계하는 데 있다. 변경 전 영향도 분석, 호환 가능한 배포 순서, 데이터 이관, 검증, 롤백 기준까지 하나의 작업으로 관리해야 실질적인 무중단 변경이 가능하다.
온라인 DDL도 완전한 무중단은 아니다
MySQL, PostgreSQL, Oracle 등 주요 데이터베이스는 운영 중 테이블 구조를 변경할 수 있는 온라인 DDL 기능을 제공한다. 그러나 온라인이라는 표현이 모든 잠금을 제거한다는 의미는 아니다. DDL을 시작하거나 종료하는 짧은 구간에 메타데이터 잠금이 발생할 수 있고, 실행 중 CPU와 디스크 I/O가 증가하면서 일반 쿼리의 응답 시간이 길어질 수 있다.
MySQL의 ALTER TABLE은 변경 유형과 버전에 따라 INSTANT, INPLACE 또는 COPY 방식으로 처리될 수 있다. INSTANT 방식은 메타데이터 중심으로 변경되기 때문에 비교적 빠르지만 모든 작업에 적용되는 것은 아니다. 테이블 재구성이 필요한 변경은 대량의 임시 공간과 긴 실행 시간이 필요할 수 있다. 운영 전에 ALGORITHM과 LOCK 옵션의 적용 가능 여부를 확인하지 않으면 예상과 달리 전체 테이블 복사가 진행될 수 있다.
PostgreSQL에서는 CREATE INDEX CONCURRENTLY를 사용하면 일반 인덱스 생성보다 쓰기 차단을 줄일 수 있다. 다만 작업 시간이 길어지고 실패 후 유효하지 않은 인덱스가 남을 가능성이 있으므로 상태 확인과 정리 절차가 필요하다. ALTER TABLE 역시 작업 종류에 따라 짧은 시간이라도 강한 잠금을 요구할 수 있다.
Oracle의 온라인 인덱스 생성과 재정의 기능도 유용하지만 작업 중 발생하는 추가 부하와 임시 공간을 고려해야 한다. 데이터베이스 제품마다 온라인 기능의 범위가 다르므로 운영 환경의 정확한 버전과 에디션을 기준으로 검증해야 한다.
확장과 축소 단계로 배포 순서를 분리한다
안전한 스키마 변경에는 확장 후 축소하는 Expand and Contract 방식이 효과적이다. 기존 컬럼을 즉시 삭제하거나 이름을 변경하는 대신 새로운 구조를 먼저 추가하고, 애플리케이션이 두 구조를 모두 처리하도록 만든 뒤 마지막에 이전 구조를 제거하는 방법이다.
예를 들어 customer_name 컬럼을 full_name으로 변경해야 한다면 운영 테이블에서 바로 컬럼명을 바꾸지 않는다. 먼저 full_name 컬럼을 추가하고 신규 애플리케이션이 두 컬럼을 함께 기록하도록 배포한다. 이후 기존 데이터를 일정 단위로 나누어 새로운 컬럼으로 이관하고, 데이터 정합성을 검증한 다음 조회 기준을 full_name으로 전환한다. 충분한 안정화 기간이 지난 뒤에만 기존 컬럼을 삭제한다.
권장 배포 순서는 다음과 같다.
- 변경 대상과 의존성을 조사한다.
- 기존 애플리케이션과 호환되는 신규 구조를 추가한다.
- 신규·기존 구조에 동시 기록하는 애플리케이션을 배포한다.
- 과거 데이터를 작은 배치 단위로 이관한다.
- 건수, 해시값, NULL 비율 등을 이용해 정합성을 확인한다.
- 조회 트래픽을 새로운 구조로 전환한다.
- 안정화 기간 이후 이전 구조를 제거한다.
이 방식은 작업 단계가 늘어난다는 단점이 있지만 특정 단계에서 문제가 발생했을 때 애플리케이션을 이전 읽기 경로로 되돌릴 수 있다. 반대로 컬럼 삭제, 데이터형 변경, 제약조건 추가를 한 번에 처리하면 장애 발생 후 되돌릴 수 있는 선택지가 크게 줄어든다.
대용량 데이터 이관은 작은 배치로 제어한다
새 컬럼을 추가한 뒤 기존 데이터를 한 번의 UPDATE 문으로 변경하면 긴 트랜잭션이 만들어진다. 이로 인해 잠금 유지 시간이 증가하고 실행 취소 영역, WAL, 리두 로그 또는 바이너리 로그가 급격히 늘어날 수 있다. 읽기 복제본을 운영하는 환경에서는 복제 지연이 누적되어 장애 조치 가능성까지 낮아질 수 있다.
대용량 데이터는 기본키나 날짜 범위를 기준으로 작은 구간으로 나눠 처리하는 것이 좋다. 각 배치가 짧은 시간 안에 커밋되도록 크기를 조절하고, 처리 사이에 대기 시간을 두어 운영 트래픽이 사용할 자원을 확보해야 한다. 처음에는 보수적인 크기로 시작한 뒤 CPU 사용률, 디스크 지연, 잠금 대기, 복제 지연을 확인하면서 점진적으로 처리량을 높이는 방식이 안전하다.
인덱스를 생성할 때도 남은 스토리지 용량을 반드시 확인해야 한다. 인덱스 최종 크기만 계산하면 부족할 수 있으며 정렬 공간, 임시 파일, 변경 로그, 복제 로그에 필요한 여유 공간까지 포함해야 한다. 스토리지 자동 확장이 설정되어 있더라도 확장 속도가 생성 속도를 따라가지 못하면 작업이 실패하거나 데이터베이스가 심각한 I/O 경합 상태에 빠질 수 있다.
제약조건 추가도 단계적으로 진행할 수 있다. 먼저 신규 데이터에만 규칙을 적용하거나 검증을 분리한 뒤 기존 데이터 정리를 완료하고 전체 검증을 수행하면 장시간 잠금 위험을 줄일 수 있다. 중요한 것은 DDL 실행 시간뿐 아니라 작업이 만들어 내는 로그량과 백그라운드 부하까지 관찰하는 것이다.
롤백 계획은 DDL 실행 전에 완성해야 한다
DDL 작업의 롤백은 애플리케이션 배포를 되돌리는 것보다 어렵다. 새로운 컬럼을 추가하는 작업은 비교적 쉽게 대응할 수 있지만 기존 컬럼 삭제, 데이터형 축소, 데이터 변환은 원본 정보를 잃을 수 있다. 따라서 변경 작업을 가역 작업과 비가역 작업으로 구분해야 한다.
롤백 계획에는 최소한 다음 내용이 포함되어야 한다.
- 중단을 결정할 수치 기준
- 이전 애플리케이션 버전의 호환 여부
- 원본 데이터 보존 위치와 보존 기간
- 변경 전 백업 및 복구 검증 결과
- 롤백 명령과 예상 소요 시간
- 작업 책임자와 승인자
- 장애 발생 시 서비스 우회 방법
중단 기준은 “부하가 높으면 중지한다”와 같이 모호하게 작성하면 안 된다. 평상시 대비 응답 시간이 두 배 이상 증가하거나, 복제 지연이 60초를 초과하거나, 잠금 대기가 일정 시간 이상 지속되는 경우처럼 측정할 수 있는 조건으로 정의해야 한다. 취소 명령을 실행했을 때 롤백 과정에서 더 많은 시간이 필요할 수 있다는 점도 고려해야 한다.
개인적으로 대용량 테이블 변경에서 가장 위험했던 상황은 DDL 자체보다 작업 종료 시점의 메타데이터 잠금이었다. 사전 테스트에서는 수십 초 안에 완료됐지만 운영 환경에서는 종료되지 않은 트랜잭션이 잠금을 보유하고 있어 DDL 대기열 뒤로 신규 요청이 쌓였다. 이때 DDL 세션만 확인하면 원인을 찾기 어렵고, 먼저 실행된 트랜잭션과 그 뒤에서 대기하는 세션 관계를 함께 살펴봐야 했다.
해결 과정에서는 신규 요청 유입을 줄이고 잠금을 보유한 세션의 트랜잭션 상태를 확인한 뒤 업무 담당자와 협의해 세션 종료 여부를 결정했다. 이후부터는 DDL 실행 전 장기 트랜잭션, idle in transaction, 메타데이터 잠금, 활성 배치 작업을 필수 점검 항목으로 추가했다. 또한 잠금 획득 제한 시간을 짧게 설정해 DDL이 무한정 기다리며 요청을 적체시키지 않도록 변경했다. 온라인 기능을 사용하더라도 실행 직전의 트랜잭션 상태가 안전성을 좌우한다는 점을 체감한 사례였다.
변경 전후 모니터링과 검증 항목
작업 전에는 테이블 크기, 행 수, 인덱스 크기, 증가 속도, 장기 실행 쿼리, 잠금 현황과 스토리지 여유 공간을 기록해야 한다. 복제 구조를 사용한다면 복제 지연과 로그 보관 공간도 함께 확인한다. 테스트 환경에서는 운영 데이터와 유사한 규모를 준비하고 동시 읽기와 쓰기 부하를 발생시킨 상태에서 변경 작업을 실행해야 의미 있는 결과를 얻을 수 있다.
작업 중에는 데이터베이스 CPU, 디스크 IOPS, 처리 지연, 잠금 대기, 활성 세션, 트랜잭션 로그 생성량과 복제 지연을 관찰한다. 애플리케이션에서는 오류율, 타임아웃, 커넥션 풀 대기 시간과 핵심 API 응답 시간을 확인해야 한다. 데이터베이스 지표만 정상이라고 해서 사용자가 체감하는 서비스까지 정상이라고 단정할 수는 없다.
작업 후에는 단순히 DDL 성공 메시지만 확인하지 말고 다음 항목을 검증해야 한다.
- 신규 컬럼 또는 인덱스 상태
- 변경 전후 전체 행 수
- NULL 및 중복 데이터 발생 여부
- 데이터 이관 누락 건수
- 주요 쿼리 실행 계획의 변화
- 복제본과 원본의 정합성
- 애플리케이션 오류 로그
- 백업과 복구 체계의 정상 동작 여부
신규 인덱스가 추가되면 옵티마이저가 기존과 다른 실행 계획을 선택할 수 있다. 계획 변경이 항상 성능 개선으로 이어지는 것은 아니므로 주요 쿼리의 처리 시간과 읽기 블록 수를 비교해야 한다. 스키마 변경 이후 통계 정보 갱신이 필요한지도 데이터베이스별로 판단해야 한다.
마치며
대규모 데이터베이스의 온라인 스키마 변경은 하나의 DDL 문장이 아니라 여러 단계로 구성된 배포 프로젝트에 가깝다. 온라인 옵션을 사용하더라도 메타데이터 잠금, 장기 트랜잭션, 로그 증가, 복제 지연과 스토리지 부족 문제는 발생할 수 있다. 따라서 운영 적용 전에 실제 데이터 규모와 동시 트래픽을 반영한 테스트가 필요하다.
가장 안전한 접근은 기존 구조를 유지한 채 새로운 구조를 추가하고, 애플리케이션 배포와 데이터 이관을 분리한 뒤 충분한 검증 기간을 거쳐 이전 구조를 제거하는 것이다. 여기에 명확한 중단 기준과 실행 가능한 롤백 계획을 준비하면 장애가 발생하더라도 서비스 영향을 제한할 수 있다.
무중단 DDL의 성공 여부는 기능 이름이 아니라 변경 과정의 가역성과 관찰 가능성에 달려 있다. 작업을 서두르기보다 각 단계에서 되돌아갈 수 있는 경로를 남기고, 데이터베이스와 애플리케이션 지표를 함께 확인하는 것이 대규모 운영 환경에서 가장 현실적인 스키마 변경 전략이다.




댓글 0
첫 댓글을 남겨보세요.