애플리케이션의 지속적인 성장을 위한 데이터베이스 스키마 진화
Emily Parker
Product Engineer · Leapcell

소개
빠르게 변화하는 소프트웨어 개발 세계에서 애플리케이션은 거의 정적이지 않습니다. 새로운 기능, 변화하는 비즈니스 요구 사항 및 사용자 피드백에 의해 끊임없이 발전합니다. 애플리케이션의 중요한 구성 요소인 데이터베이스 스키마는 종종 이러한 변경 사항의 대부분을 부담합니다. 전통적으로 스키마 수정은 위험으로 가득 차 있었으며, 종종 서비스 중단 시간, 복잡한 마이그레이션 스크립트, 그리고 데이터 손실 또는 서비스 중단의 끊임없는 위험을 필요로 했습니다. 이러한 문제는 지속적인 배포 및 고가용성을 목표로 하는 애플리케이션에 특히 두드러집니다. 활성 서비스를 방해하지 않고 데이터베이스 스키마(열 추가, 수정 또는 삭제)를 우아하게 발전시킬 수 있는 능력은 더 이상 사치가 아니라 민첩성을 유지하고 중단 없는 사용자 경험을 보장하기 위한 기본 요구 사항입니다. 이 문서는 원활한 스키마 진화를 가능하게 하여 데이터베이스가 애플리케이션과 함께 성장하고 적응할 수 있도록 하는 전략과 기법을 자세히 살펴봅니다.
스키마 진화의 환경 이해
실무에 들어가기 전에 데이터베이스 스키마 진화와 관련된 몇 가지 핵심 개념을 이해하는 것이 중요합니다.
스키마 버전 관리: 코드에 버전이 있듯이 데이터베이스 스키마에도 버전이 있을 수 있습니다. 스키마 버전 관리 시스템은 시간이 지남에 따라 데이터베이스 구조의 변경 사항을 추적하여 자동화된 마이그레이션 및 롤백을 가능하게 합니다. Flyway 또는 Liquibase와 같은 도구는 스키마 버전 관리에 널리 사용됩니다.
하위 호환성: 데이터베이스 변경이 하위 호환되는 것은 이전 버전의 애플리케이션이 새 스키마와 올바르게 상호 작용할 수 있음을 의미합니다. 이는 애플리케이션 배포가 분할될 수 있거나 전환 중에 여러 버전의 애플리케이션이 공존하는 환경에서 중요합니다.
상위 호환성: 데이터베이스 변경이 상위 호환되는 것은 새 버전의 애플리케이션이 이전 스키마와 올바르게 상호 작용할 수 있음을 의미합니다. 이것은 일반적으로 달성하기 더 어렵고 종종 덜 강조되지만, 새 스키마를 유지하면서 새 애플리케이션 버전을 롤백하는 시나리오와 관련될 수 있습니다.
제로 다운타임 배포(ZDD): 데이터베이스 스키마 변경의 궁극적인 목표는 서비스 중단 없이 실행하는 것입니다. 이는 종종 이전 및 새 애플리케이션 코드가 스키마 진화와 공존할 수 있도록 신중하게 조율된 단계를 포함합니다.
온라인 스키마 마이그레이션: 이는 데이터베이스가 온라인 상태로 유지되면서 스키마를 변경하고 읽기 및 쓰기 작업에 액세스할 수 있음을 의미합니다. 최신 데이터베이스 시스템은 종종 이를 촉진하는 기능을 제공하지만 신중한 계획은 여전히 필요합니다.
새 열 추가 전략
새 열을 추가하는 것은 일반적으로 가장 안전한 스키마 변경이지만 여전히 서비스 영향을 방지하기 위해 신중한 고려가 필요합니다.
가장 간단한 접근 방식은 Null 허용 열을 추가하는 것입니다. 기존 애플리케이션 코드는 새 열을 무시하므로 본질적으로 하위 호환됩니다.
-- 예: 'users' 테이블에 Null 허용 'email' 열 추가 ALTER TABLE users ADD COLUMN email VARCHAR(255);
새 열이 Null 불가능해야 하는 경우 프로세스가 더 복잡해집니다.
-
Null 허용 열 추가: 위와 같이
ALTER TABLE ADD COLUMN
작업을 수행합니다.ALTER TABLE users ADD COLUMN email VARCHAR(255);
-
새 애플리케이션 코드 배포: 새 열에 데이터를 쓰기 시작하도록 애플리케이션을 업데이트합니다. 새 코드가 기존 레코드를 읽을 때 초기
NULL
값을 처리하도록 합니다. -
기존 데이터 채우기(선택 사항이지만 종종 필요): 새 열을 기존 행에 대해 채워야 하는 경우 별도의 스크립트 또는 백그라운드 작업을 실행합니다. 이는 테이블을 장시간 잠그지 않기 위해 배치로 수행할 수 있습니다.
-- 예: 기존 사용자의 이메일 채우기 (단순화) UPDATE users SET email = 'default@example.com' WHERE email IS NULL;
-
열을 Null 불가능으로 변경: 모든 기존 데이터가 채워지고 새 애플리케이션 코드가 안정화되면 열을 Null 불가능으로 만들 수 있습니다. 이 단계는 데이터베이스 시스템에 따라 테이블에 대한 짧은 잠금을 여전히 필요로 할 수 있습니다.
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
열 수정 기법
기존 열을 수정하는 것은 특히 데이터 유형이나 제약 조건이 포함된 경우 더 어려울 수 있습니다. 핵심은 전환 중에 하위 호환성을 유지하는 것입니다.
열 이름 바꾸기: 직접 열 이름을 바꾸면 기존 애플리케이션 코드가 손상될 수 있습니다. 일반적인 접근 방식은 여러 단계로 이루어집니다.
- 원하는 이름과 유형으로 새 열 추가:
ALTER TABLE products ADD COLUMN new_price DECIMAL(10, 2);
- 데이터 동기화: 트리거나 백그라운드 작업을 사용하여 이전 열에서 새 열로 데이터를 복사합니다. 이를 통해 전환 중에 두 열에 동일한 데이터가 유지됩니다.
-- 예 (PostgreSQL 트리거, 단순화) CREATE OR REPLACE FUNCTION copy_price_func() RETURNS TRIGGER AS $$ BEGIN NEW.new_price := NEW.old_price; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER copy_price_trigger BEFORE INSERT OR UPDATE ON products FOR EACH ROW EXECUTE FUNCTION copy_price_func(); -- 기존 데이터도 채웁니다. UPDATE products SET new_price = old_price;
- 새 애플리케이션 코드 배포: 애플리케이션을 업데이트하여
new_price
열을 읽고 씁니다. 이전 코드는 여전히old_price
를 사용합니다. - 이전 열 삭제: 새 애플리케이션 코드가 완전히 배포되고 안정화되어 더 이상
old_price
에 의존하는 이전 코드 경로가 없다고 확신하면 이전 열을 안전하게 삭제합니다.ALTER TABLE products DROP COLUMN old_price;
열 데이터 유형 변경: 이름 바꾸기와 유사하게 데이터 유형을 직접 변경하면 종종 열을 삭제하고 다시 추가해야 하므로 파괴적입니다. 더 안전한 접근 방식은 다음과 같습니다.
- 원하는 데이터 유형으로 새 열 추가:
ALTER TABLE events ADD COLUMN new_timestamp TIMESTAMP WITH TIME ZONE;
- 데이터 동기화: 이전 열에서 새 열로 데이터를 복사하고 변환합니다. 여기에는 유형 캐스팅이 포함될 수 있습니다.
UPDATE events SET new_timestamp = old_timestamp::TIMESTAMP WITH TIME ZONE;
- 새 애플리케이션 코드 배포: 애플리케이션이
new_timestamp
열 사용을 시작합니다. - **이전 열 삭제.
열 삭제 원칙
열을 삭제하는 것은 가장 파괴적인 스키마 변경이며 가장 신중한 접근이 필요합니다. 주요 전략은 먼저 사용 중단시키는 것입니다.
-
애플리케이션 코드에서 사용 중단: 열에 쓰는 것을 중지하고 읽을 때 해당 값을 무시하도록 애플리케이션 코드를 수정합니다. 그러나 열은 여전히 데이터베이스에 존재합니다. 이 버전을 배포합니다.
-
사용량 모니터링: 애플리케이션의 어떤 부분 또는 외부 서비스도 여전히 사용 중단된 열에 의존하지 않는지 확인합니다. 가능하다면 데이터베이스 모니터링 도구를 활용하여 열 액세스 패턴을 추적합니다.
-
유예 기간: 모든 이전 버전의 애플리케이션이 프로덕션에서 제거되었고 잊혀진 종속성이 식별되지 않았는지 확인하기 위해 상당한 유예 기간(몇 주 또는 몇 달)을 허용합니다.
-
열 삭제: 열이 더 이상 사용되지 않는다고 절대적으로 확신하면 안전하게 삭제할 수 있습니다.
ALTER TABLE orders DROP COLUMN old_deprecated_field;
보호되거나 중요한 데이터에 대해 물리적으로 열(또는 행)을 제거하는 대신 '삭제됨' 플래그를 설정하는 소프트 삭제를 고려하는 것도 현명합니다. 이것은 열 삭제를 직접적으로 다루지는 않지만 데이터 제거에 대한 신중한 접근 방식을 보여줍니다.
실제 고려 사항 및 도구
- 데이터베이스별 기능: 최신 RDBMS(PostgreSQL, MySQL, SQL Server)는 다양한 온라인 스키마 마이그레이션 기능을 제공합니다. PostgreSQL의
ALTER TABLE ADD COLUMN ... DEFAULT ... NOT NULL
은 기존 행에 대한UPDATE
단계에서 잠금이 필요하지만 Null 불가능 열을 전체 테이블 다시 쓰기 없이 추가하는 데 매우 빠를 수 있습니다. MySQL 5.6 이상에서ALGORITHM=INSTANT
또는INPLACE
를 사용하면 특정ALTER TABLE
작업을 훨씬 빠르게 수행할 수 있습니다. 항상 데이터베이스 문서를 참조하십시오. - 프록시 도구: MySQL용 Percona Toolkit의
pt-online-schema-change
또는 gh-ost(GitHub의 온라인 스키마 마이그레이션 도구)와 같은 도구는 새 테이블을 만들고 데이터를 복사하고 변경 사항을 적용한 다음 테이블을 교환하여 제로 다운타임 변경을 달성합니다. 이들은 대규모 테이블에 매우 효과적입니다. - 기능 플래그: 스키마 변경이 필요한 새 기능을 도입할 때 기능 플래그를 사용하면 스키마 변경 배포와 새 애플리케이션 로직 배포를 분리할 수 있습니다. 이를 통해 기능을 롤아웃하고 문제가 발생할 경우 롤백하는 데 더 많은 제어를 할 수 있습니다.
- 자동화된 테스트: 철저한 테스트, 통합 테스트 및 프로덕션에서의 A/B 테스트를 포함하여 스키마 변경 후에는 매우 중요합니다.
결론
계속 성장하는 애플리케이션을 위해 데이터베이스 스키마를 진화시키는 것은 전략적이고 신중한 접근 방식을 요구합니다. 하위 호환성 개념을 이해하고, 다단계 배포 전략을 사용하고, 데이터베이스별 기능 또는 특수 도구를 활용함으로써 서비스 가용성을 희생하지 않고 열을 추가, 수정 및 삭제할 수 있습니다. 민첩한 스키마 진화로의 여정은 신중한 계획, 점진적인 변경 및 엄격한 테스트의 여정으로, 애플리케이션 아키텍처가 끊임없는 변화의 바람에 유연하고 복원력을 유지하도록 보장합니다.