infra
Platform

모듈 맵

[Infra Ops] DDL 반영 절차와 Migration 안전 운영

0 / 52 완료

펼치기
0 / 52 완료0%

인프라 운영 & SRE · 36 / 52

[Infra Ops] DDL 반영 절차와 Migration 안전 운영

운영 DB DDL 반영 절차, Flyway/Liquibase 개념, 반영 전후 확인, 롤백 계획까지 — 서비스 중단 없이 DB 스키마를 변경하는 실무

🚨INCIDENT ALERT
HIGH

오전 배포 직전, 개발팀에서 "DB 컬럼 하나 추가해야 합니다"라는 요청이 왔습니다. 간단해 보입니다. 그런데 그 테이블에 데이터가 5000만 건 있습니다. ALTER TABLE을 실행하는 순간 테이블에 Lock이 걸리고, 그 시간 동안 서비스의 모든 쓰기 요청이 블로킹됩니다. 몇 분이면 되는 줄 알았던 작업이 20분짜리 서비스 장애로 변할 수 있습니다.

이 모듈은 운영 DB 스키마 변경을 안전하게 처리하는 절차를 다룹니다. DDL 반영 전 체크리스트, Flyway 버전 관리, 대용량 테이블 무중단 변경, 롤백 준비까지 포함합니다.

이번 챕터에서 배울 것
  • 1DDL 반영 전 체크리스트(백업/영향도/Lock 예상/롤백 스크립트)를 작성할 수 있다
  • 2개발DB → 검증DB → 운영DB 순서의 반영 절차를 설명할 수 있다
  • 3Flyway 마이그레이션 파일 명명 규칙을 이해하고 실행 이력을 확인할 수 있다
  • 4pt-online-schema-change를 써야 하는 상황(대용량 테이블)을 판단할 수 있다
  • 5잘못된 DDL 반영 후 롤백 스크립트를 실행하는 절차를 따라할 수 있다

DDL 반영 절차 — 반드시 이 순서로

💡개념

개발 → 검증 → 운영 순서와 체크리스트

운영 DB에 DDL을 곧바로 적용하는 것은 위험합니다. 검증되지 않은 SQL이 운영 데이터를 망가뜨리거나 서비스를 중단시킬 수 있습니다. 항상 아래 순서를 따릅니다.

DB 마이그레이션 순서와 체크리스트 — DDL은 개발 → 검증(스테이징) → 운영 순서로 단계마다 적용·확인. 각 단계에서 백업·롤백 SQL 준비, 실행계획 검토, 영향 범위 확인을 거침. 검증되지 않은 SQL을 운영에 바로 적용하면 데이터 손상·서비스 중단 위험확대

1. 개발 DB (dev)     → SQL 작성 및 기본 검증
2. 스테이징 DB (stg) → 운영과 동일한 데이터 구조로 검증
3. 운영 DB (prod)    → 체크리스트 통과 후 최종 반영

운영 DB DDL 반영 전 체크리스트:

항목확인 방법필수 여부
DB 백업 완료mysqldump 또는 스냅샷 확인필수
영향 테이블 크기 확인SHOW TABLE STATUS필수
Lock 예상 시간 산정스테이징에서 실행 시간 측정필수
접속 세션 수 확인SHOW PROCESSLIST필수
롤백 스크립트 준비UNDO SQL 작성 완료필수
점검 시간 또는 트래픽 저점 확인모니터링 대시보드필수
DB 클라이언트
# 영향 테이블 크기 확인
mysql -h db-server -u dba -p mydb -e "
  SELECT
    table_name,
    table_rows,
    ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
  FROM information_schema.tables
  WHERE table_schema = 'mydb'
  AND table_name = 'users';
"

# 현재 접속 세션 수 확인
mysql -h db-server -u dba -p mydb -e "SHOW PROCESSLIST;"
mysql -h db-server -u dba -p mydb -e "SELECT COUNT(*) FROM information_schema.processlist;"
💡개념

마이그레이션 하나가 운영에 안전하게 반영되기까지 — 작성부터 롤백까지 7단계

"컬럼 하나 추가"라는 한 줄 요청도, 운영 DB에 닿기까지는 정해진 단계를 거쳐야 안전합니다. 이 흐름을 알면 배포가 틀어졌을 때 "어느 단계까지 갔나"로 대응을 좁힐 수 있습니다 — 운영에 손대기 전이면 SQL만 고치면 되고, 반영 도중이면 취소·전환, 반영 후 이상이면 롤백입니다. 아래는 변경 SQL 한 개가 요청에서 반영(또는 안전한 롤백)까지 지나는 7단계입니다.

TEXT
[변경 요청]  "users에 phone 컬럼 추가"
   │
   ① 작성        변경 SQL + 되돌릴 UNDO SQL을 한 쌍으로   (V10__add / V10__undo)
   │              → 비가역 DDL(DROP·TRUNCATE)은 여기서 표시하고 백업을 전제로
   │
   ② 개발 검증    dev DB에서 실행 → 문법·제약 충돌·결과 확인
   │
   ③ 스테이징 실측 운영과 같은 행수 테이블에서 time으로 Lock·소요 시간 측정
   │
   ④ 방식 판단    크기·Lock 영향으로 결정
   │              작으면 직접 ALTER / 크면 pt-osc·gh-ost (온라인)
   │
   ⑤ 백업·시점    논리·물리 백업 확인 + 트래픽 저점/점검창 확보
   │
   ⑥ 운영 적용    SQL 또는 온라인 도구로 반영
   │              → 복제 지연·PROCESSLIST 감시
   │
   ⑦ 검증         SHOW COLUMNS·DESCRIBE로 확인
   ▼              이상 → 준비한 UNDO SQL로 롤백
[반영 완료 또는 안전 롤백]

각 단계에서 무슨 일을 하고, 틀리면 어떤 증상인가:

단계하는 일여기서 틀리면
① 작성변경 SQL과 UNDO SQL을 짝으로 작성. DROP·TRUNCATE처럼 되돌릴 수 없는 DDL은 별도 표시하고 백업을 전제로UNDO 없이 진행 → 사고 시 되돌릴 방법이 없음(DROP COLUMN은 데이터까지 소실)
② 개발 검증dev DB에서 실행해 문법·제약·결과 확인여기서 실패하면 운영 이전이라 안전 — 문법 오류·제약 충돌을 이 단계에서 잡는다
③ 스테이징 실측운영과 같은 행수에서 time으로 Lock·소요 시간 측정실측 생략 → 운영에서 예상 못 한 수십 분 Lock으로 쓰기 전면 블로킹
④ 방식 판단크기·Lock 영향으로 직접 ALTER인지 온라인 도구(pt-osc·gh-ost)인지 결정대용량을 직접 ALTER → Waiting for metadata lock으로 서비스 장애
⑤ 백업·시점논리/물리 백업 확인 + 트래픽 저점·점검창 확보백업 없이 적용 → 롤백 SQL로도 못 살리는 데이터는 복구 불가
⑥ 운영 적용SQL·온라인 도구로 반영하며 복제 지연·PROCESSLIST 감시복제 지연 방치 → replica에서 stale read, 청크 write가 부하 유발
⑦ 검증·롤백SHOW COLUMNS·DESCRIBE로 반영 확인, 이상하면 UNDO SQL 실행검증 없이 완료 선언 → 부분 반영·인덱스 누락을 배포 후에야 발견

즉 "운영 반영 성공"은 세 가지가 모두 참이라는 뜻입니다 — 되돌릴 UNDO가 준비됐고(①), 예상 Lock 시간이 실측으로 확인됐으며(③④), 반영 후 스키마가 검증됐다(⑦). 문제가 생기면 이 단계 중 어디까지 갔는지로 대응이 갈립니다 — ④ 이전이면 아직 운영에 손대기 전이라 SQL만 고치면 되고, ⑥ 도중이면 진행 중 ALTER를 취소(완료 전이면 원상 복귀)하거나 온라인 도구로 전환하며, ⑦에서 이상이 드러나면 곧바로 UNDO SQL로 롤백합니다. 그래서 ①의 UNDO 준비와 ③의 실측이 나머지 전부를 좌우합니다.

DDL 실행과 확인

💡개념

운영 DB에서 DDL 반영하는 방법

실제 DDL을 운영 DB에 적용하는 명령입니다. SQL 파일로 관리해서 실수를 줄이고, 적용 전후 스키마를 확인합니다.

무중단 DDL 반영 방법 — 대용량 테이블의 ALTER는 테이블을 장시간 잠가 서비스를 멈출 수 있음. online DDL(pt-online-schema-change·gh-ost)이나 새 컬럼 추가 후 백필→교체 방식으로 잠금을 피함. SQL 파일로 관리해 실수를 줄이고 적용 전후 스키마를 비교 확인확대

로컬 터미널
# 1. 백업 확인 (반드시 먼저)
ls -lh /backup/mydb_$(date +%Y%m%d)*.sql 2>/dev/null || echo "WARNING: 오늘 백업 없음"

# 2. DDL 파일 내용 최종 확인
cat /tmp/V10__add_user_phone_column.sql
# ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER email;

# 3. 스테이징에서 실행 시간 측정 (운영 전 반드시)
time mysql -h stg-db-server -u dba -p mydb < /tmp/V10__add_user_phone_column.sql

# 4. 운영 DB 적용
mysql -h db-server -u dba -p mydb < /tmp/V10__add_user_phone_column.sql

# 5. 적용 결과 확인
mysql -h db-server -u dba -p mydb -e "SHOW COLUMNS FROM users LIKE 'phone';"

# 6. 스키마 전체 확인
mysql -h db-server -u dba -p mydb -e "DESCRIBE users;"

롤백 스크립트 — 모든 DDL에 대응하는 UNDO SQL:

SQL
-- V10__add_user_phone_column.sql (적용)
ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER email;

-- V10__undo_add_user_phone_column.sql (롤백용)
ALTER TABLE users DROP COLUMN phone;
DB 클라이언트
# 잘못 적용됐을 때 롤백
mysql -h db-server -u dba -p mydb < /tmp/V10__undo_add_user_phone_column.sql
mysql -h db-server -u dba -p mydb -e "DESCRIBE users;"  # 컬럼 사라졌는지 확인

Flyway — DB 마이그레이션 버전 관리

💡개념

Flyway 마이그레이션 파일 구조

Flyway는 SQL 스크립트를 버전 순서대로 실행하고 이력을 기록하는 도구입니다. "어느 환경에 어느 SQL까지 반영됐나"를 추적할 수 있어 환경 간 스키마 불일치를 방지합니다.

파일 명명 규칙:

V{버전}__{설명}.sql

src/main/resources/db/migration/ 구조입니다.

  • V1__create_users_table.sql
  • V2__create_orders_table.sql
  • V3__add_email_index.sql
  • V9__add_product_category.sql
  • V10__add_user_phone_column.sql
SQL
-- V10__add_user_phone_column.sql
ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER email;
CREATE INDEX idx_users_phone ON users(phone);
로컬 터미널
# Spring Boot + Flyway 마이그레이션 실행
# 애플리케이션 기동 시 자동 실행, 또는 수동 실행:
mvn flyway:migrate -Dflyway.url=jdbc:mysql://db-server:3306/mydb \
    -Dflyway.user=dba -Dflyway.password=${DB_PASSWORD}

# 마이그레이션 이력 확인
mvn flyway:info

# 또는 DB에서 직접 확인
mysql -h db-server -u dba -p mydb -e "SELECT * FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 10;"
OUTPUT
+--------------+---------+------------------------------+---------+---------------------+---------+
| installed_rank | version | description                 | success | installed_on        | checksum|
+--------------+---------+------------------------------+---------+---------------------+---------+
|           10 | 10      | add user phone column        |       1 | 2026-05-30 10:30:00 | 12345678|
|            9 | 9       | add product category         |       1 | 2026-05-28 15:00:00 | 87654321|

대용량 테이블 무중단 변경

💡개념

pt-online-schema-change — Lock 없는 ALTER

테이블 크기가 수천만 건 이상이면 일반 ALTER TABLE은 장시간 Lock을 유발합니다. pt-online-schema-change(pt-osc)는 이 문제를 해결하는 Percona 도구입니다. 원본 테이블을 사용하면서 백그라운드에서 새 테이블에 데이터를 복사한 뒤 atomic rename으로 교체합니다.

로컬 터미널
# pt-online-schema-change 설치
yum install percona-toolkit
# 또는
apt-get install percona-toolkit

# 기본 사용법 (컬럼 추가 예시)
pt-online-schema-change \
  --alter "ADD COLUMN phone VARCHAR(20) NULL AFTER email" \
  --host=db-server \
  --user=dba \
  --password=${DB_PASSWORD} \
  --database=mydb \
  --table=users \
  --execute

# 실행 전 dry-run (실제 실행 없이 계획만 출력)
pt-online-schema-change \
  --alter "ADD COLUMN phone VARCHAR(20) NULL AFTER email" \
  --host=db-server --user=dba --password=${DB_PASSWORD} \
  --database=mydb --table=users \
  --dry-run

# 진행 상황 모니터링 (별도 터미널)
watch -n 5 "mysql -h db-server -u dba -p mydb -e 'SHOW TABLE STATUS LIKE \"_users_new\"'"

pt-osc 사용 판단 기준:

테이블 크기권장 방법
100만 건 이하일반 ALTER TABLE (Lock 몇 초)
100만~1000만 건트래픽 저점(새벽 2~4시)에 ALTER TABLE
1000만 건 초과pt-online-schema-change 사용

실습

1DDL 반영 전 사전 점검

DDL 적용 전 영향받는 테이블의 크기와 현재 접속 세션을 확인합니다. 이 정보로 Lock 시간을 예측하고 작업 시간대를 결정합니다.

DB 클라이언트
# 영향 테이블 크기 확인
mysql -h localhost -u root -p mydb -e "
  SELECT table_name,
    table_rows,
    ROUND((data_length+index_length)/1024/1024, 2) AS size_mb
  FROM information_schema.tables
  WHERE table_schema = 'mydb' AND table_name = 'users';"

# 현재 진행 중인 쿼리 확인
mysql -h localhost -u root -p -e "SHOW FULL PROCESSLIST;" | grep -v "Sleep"

# 테이블 Lock 상태 확인
mysql -h localhost -u root -p -e "SHOW OPEN TABLES WHERE In_use > 0;"
OUTPUT
+------------+------------+---------+
| table_name | table_rows | size_mb |
+------------+------------+---------+
| users      |   52483201 | 4523.45 |
+------------+------------+---------+
mysql -h localhost -u root -p -e 'SELECT table_name, table_rows, ROUND((data_length+index_length)/1024/1024,2) AS size_mb FROM information_schema.tables WHERE table_schema=DATABASE() ORDER BY size_mb DESC LIMIT 10;'
🔍실행 후 확인할 것
  • table_rows 값을 먼저 확인 — 1000만 건 이하면 직접 ALTER 가능, 초과하면 Lock 시간이 수십 분 이상 걸려 서비스 영향. pt-online-schema-change 또는 gh-ost 사용 검토
  • SHOW PROCESSLIST의 Time 컬럼에서 60초 이상 실행 중인 쿼리가 있으면 DDL 보류 — ALTER TABLE은 해당 트랜잭션이 끝날 때까지 대기하며 그 사이 신규 요청도 모두 블로킹됨
  • 테이블 크기가 크고 장시간 쿼리도 있는 조합이면 — 새벽 트래픽 최저 시간대(보통 02:00~05:00)로 점검 일정을 변경하고 롤백용 UNDO SQL을 미리 준비한 뒤 진행
2Flyway 마이그레이션 실행 및 이력 확인

Flyway가 적용된 프로젝트라면 flyway_schema_history 테이블에서 현재 반영된 스키마 버전을 확인할 수 있습니다. 어느 환경에 어느 버전까지 적용됐는지 추적하는 데 사용합니다.

DB 클라이언트
# flyway_schema_history 이력 확인
mysql -h localhost -u root -p mydb -e "
  SELECT installed_rank, version, description, success, installed_on
  FROM flyway_schema_history
  ORDER BY installed_rank DESC LIMIT 5;"

# 아직 적용 안 된 마이그레이션 확인 (Spring Boot 프로젝트에서)
# 비밀번호는 ~/.flyway.conf(권한 600) 또는 Secret Manager 연동으로 주입합니다.
mvn flyway:info -Dflyway.url=jdbc:mysql://localhost:3306/mydb \
    -Dflyway.user=flyway_app 2>/dev/null | grep "Pending\|Success"
OUTPUT
+--------------+---------+---------------------------+---------+---------------------+
| installed_rank | version | description              | success | installed_on        |
+--------------+---------+---------------------------+---------+---------------------+
|           10 |      10 | add user phone column     |       1 | 2026-05-30 10:30:00 |
|            9 |       9 | add product category      |       1 | 2026-05-28 15:00:00 |
mysql -h localhost -u root -p mydb -e 'SELECT installed_rank, version, description, success, installed_on FROM flyway_schema_history ORDER BY installed_rank DESC LIMIT 5;'
🔍실행 후 확인할 것
  • flyway_schema_history에서 success=0인 행을 먼저 찾는다 — 있으면 해당 버전의 SQL이 실패한 것. Flyway는 실패한 마이그레이션이 있으면 이후 버전 적용을 거부함
  • 최신 installed_rank의 version이 stg와 prod에서 다르면 환경 불일치 — 차이가 1~2개면 미적용 마이그레이션, 10개 이상이면 환경별 배포 절차가 분리된 것으로 즉시 원인 파악 필요
  • success=0이 있고 실제 스키마 상태가 불일치한 조합이면 — DESCRIBE TABLE로 현재 스키마를 확인하고 실패 지점 이전 상태로 수동 복구 후 flyway repair 명령 실행

트러블슈팅

원인: 다른 세션이 테이블을 사용하는 상태에서 ALTER TABLE이 메타데이터 Lock을 기다리고 있습니다. ALTER 자체가 Lock을 걸기도 하지만, 이미 열린 트랜잭션이 있으면 그 트랜잭션이 끝날 때까지 대기합니다.

DB 클라이언트
# 1. Lock 대기 상태 확인
mysql -e "SELECT * FROM information_schema.INNODB_LOCK_WAITS;"
mysql -e "SELECT r.trx_id waiting_trx, r.trx_mysql_thread_id waiting_thread,
          b.trx_id blocking_trx, b.trx_mysql_thread_id blocking_thread
          FROM information_schema.INNODB_LOCK_WAITS w
          JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id
          JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;"

# 2. 블로킹 세션 확인 및 종료 (DBA 판단 후)
mysql -e "SHOW FULL PROCESSLIST;" | grep -v Sleep
# 장시간 실행 중인 세션 ID 확인 후
mysql -e "KILL <세션ID>;"

# 3. 즉시 대안 — ALTER 취소 후 pt-osc로 전환
# Ctrl+C 로 ALTER 취소 (완료 전이면 테이블 원상 복귀)
# pt-online-schema-change 사용
pt-online-schema-change \
  --alter "ADD COLUMN phone VARCHAR(20) NULL AFTER email" \
  --host=localhost --user=dba --password=${DB_PASSWORD} \
  --database=mydb --table=users \
  --execute --no-drop-old-table

재발 방지: 테이블 크기를 DDL 전에 항상 확인하고, 1000만 건 이상은 pt-osc를 기본으로 사용합니다.

원인: 롤백 스크립트가 준비되지 않은 상태에서 잘못된 DDL이 실행됐습니다. DROP COLUMN은 해당 컬럼의 데이터까지 삭제합니다.

DB 클라이언트
# 즉각 조치 순서

# 1. 추가 변경 즉시 중단
# 더 이상의 DML(INSERT/UPDATE/DELETE) 최소화

# 2. 백업에서 해당 컬럼 데이터 복구 가능 여부 확인
mysqldump --no-create-info mydb users > /tmp/users_backup_check.sql
grep "phone" /tmp/users_backup_check.sql | head -5

# 3. 백업 DB에서 데이터 추출
mysql -h backup-db-server -u dba -p mydb -e "
  SELECT id, phone FROM users LIMIT 10;"

# 4. 컬럼 재생성 후 백업 데이터 복구
mysql -h db-server -u dba -p mydb -e "
  ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER email;"

# 백업 데이터로 UPDATE
mysql -h db-server -u dba -p mydb << 'EOF'
UPDATE users u
JOIN backup_users b ON u.id = b.id
SET u.phone = b.phone
WHERE b.phone IS NOT NULL;
EOF

# 5. 복구 건수 확인
mysql -h db-server -u dba -p mydb -e "
  SELECT COUNT(*) FROM users WHERE phone IS NOT NULL;"

핵심 교훈: DROP COLUMN, DROP TABLE, TRUNCATE를 포함한 모든 DDL은 실행 전 UNDO SQL을 준비합니다. 백업이 없으면 DROP으로 삭제된 데이터는 복구 불가능합니다.

심화 — 온라인 DDL은 '긴 락'만 없앨 뿐이다

💡개념

심화: pt-osc·gh-ost가 만능이 아닌 이유 — 전제와 한계

"pt-osc를 붙이면 무조건 무중단"이라고 믿으면, 정작 외래키가 걸린 테이블이나 복제 클러스터에서 사고가 납니다. 도구가 무엇을 없애 주고 무엇은 그대로 두는지를 알아야 안전합니다.

  • 트리거 기반 vs binlog 기반: pt-osc는 원본에 트리거를 걸어 진행 중 변경을 따라 씁니다. 그래서 원본에 이미 애플리케이션 트리거가 있으면 충돌하고, 트리거 실행 오버헤드가 write에 얹힙니다. gh-ost는 트리거 대신 binlog를 읽어 이 제약을 피하지만, row 기반 binlog와 읽을 수 있는 복제 위치를 전제로 합니다.
  • 외래키(FK)의 함정: pt-osc는 원본을 새 테이블로 rename하면서 자식 테이블의 FK를 다시 연결해야 합니다. --alter-foreign-keys-method=rebuild_constraints는 자식 테이블을 다시 ALTER하므로 자식이 크면 또 오래 걸리고, drop_swap은 짧지만 순간적으로 FK가 없는 위험한 틈이 생깁니다. FK가 많은 스키마는 온라인 DDL의 가장 큰 함정입니다.
  • 복제 지연과 디스크: 청크 복사는 대량 write를 만들어 복제 지연(replica lag)을 키웁니다. pt-osc는 --max-lag로 스스로 속도를 늦추지만 그만큼 작업이 길어집니다. 또 새 테이블은 원본 크기만큼의 추가 디스크를 쓰므로, 1000만 건이 넘는 테이블이면 여유 공간을 먼저 확인하고 중간 실패 시 남는 _table_new·_table_old 잔여 테이블 정리까지 계획해야 합니다.
  • 한계 요약: 온라인 DDL은 '긴 락'을 없앨 뿐, 디스크·복제·FK·부하는 그대로 옮겨 옵니다. 그래서 실행 전 --dry-run으로 FK 처리 방식과 단계를 확인하고, 트래픽 저점에 복제 지연을 모니터링하며 돌리는 절차는 여전히 필요합니다.

상황: orders에 컬럼을 추가하려 pt-osc를 --execute로 돌렸습니다. orders를 외래키로 참조하는 order_items(수천만 건)가 있습니다. 진행률이 좀처럼 오르지 않고, 읽기 복제본의 지연이 수백 초까지 치솟아 앱이 stale 데이터를 보여 줍니다.

원인: pt-osc가 orders를 새 테이블로 교체하면서 order_items의 외래키를 재구성해야 하는데, 기본이 rebuild_constraints라 대용량 order_items를 다시 ALTER하느라 시간이 폭증했습니다. 동시에 청크 복사 write가 복제 지연을 밀어 올렸습니다. 실행 전 --dry-run으로 외래키 처리 방식을 확인하지 않은 것이 근본 원인입니다.

진단: SHOW FULL PROCESSLIST에서 pt-osc가 자식 테이블 ALTER 단계에 머물러 있는지 확인합니다. 복제 상태(SHOW REPLICA STATUS의 Seconds_Behind_Source)와 pt-osc 로그의 --max-lag throttle 메시지를 함께 봅니다. 자식 테이블 크기를 information_schema로 재확인하면 rebuild 비용이 왜 큰지 드러납니다.

해결: 이런 케이스는 트리거 없이 binlog 기반으로 도는 gh-ost를 검토하거나, 트래픽 저점에 외래키를 잠시 제거→변경→재생성하는 계획으로 전환합니다. --max-lag·--chunk-time으로 부하를 제한해 복제 지연을 억제하고, 자식 테이블 크기를 사전에 산정해 예상 시간을 잡습니다. 재발 방지의 핵심은 대용량·FK 테이블에서는 반드시 --dry-run으로 외래키 처리 방식과 단계를 먼저 확인하는 것입니다.

💼
실무 맥락
현업 패턴

실제 업무에서 이 지식이 쓰이는 상황:

DB 스키마 변경은 인프라 엔지니어와 DBA가 협업하는 대표적인 작업입니다.

1. 정기 배포 시 DDL 반영 절차:

로컬 터미널
# 배포 당일 오전 체크리스트 실행
# ① 백업 확인
ls -lh /backup/$(date +%Y%m%d)/mydb*.sql

# ② 스테이징에서 DDL 실행 시간 측정
time mysql -h stg-db -u dba -p mydb < /deploy/V10__add_column.sql

# ③ 운영 적용 (트래픽 저점 시간 또는 점검 시간)
mysql -h prod-db -u dba -p mydb < /deploy/V10__add_column.sql

# ④ 검증
mysql -h prod-db -u dba -p mydb -e "DESCRIBE users;" | grep phone

2. Flyway로 스키마 버전 관리: 인프라 팀이 여러 환경(dev/stg/prod)의 스키마 버전을 추적합니다.

로컬 터미널
# 각 환경의 현재 Flyway 버전 확인 스크립트
for env in dev stg prod; do
  echo "=== $env ==="
  mysql -h ${env}-db -u dba -p${DB_PASS} mydb \
    -e "SELECT MAX(version) as current_version, MAX(installed_on) as last_migration FROM flyway_schema_history WHERE success=1;"
done

3. 긴급 롤백 판단: DDL 문제는 애플리케이션 재배포로는 해결되지 않습니다. 스키마 자체를 되돌려야 합니다. 그래서 롤백 스크립트는 배포 패키지와 함께 항상 준비해야 합니다.

명령어·단축키 빠른 참조

이 모듈에서 다룬 DDL 반영·마이그레이션 명령을 안전 옵션과 함께 모았습니다. 운영 반영 전 "예" 열 순서를 그대로 밟으면 됩니다.

명령어/단축키용도자주 쓰는 예
mysqldumpDDL 전 논리 백업(필수)mysqldump mydb users > users_$(date +%F).sql
SHOW TABLE STATUS행수·크기로 Lock 시간 예측information_schema.tables에서 size_mb 조회
SHOW FULL PROCESSLIST실행 중 세션·장시간 쿼리 확인Time 60초 이상 쿼리 있으면 DDL 보류
time mysql < file.sql스테이징에서 DDL 시간 측정운영 반영 전 Lock 시간 산정
ALTER TABLE소용량 직접 스키마 변경ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL
pt-online-schema-change대용량 무중단 ALTER(1000만 건↑)--alter "ADD COLUMN ..." --execute --max-lag=1
pt-osc --dry-run실행 전 계획·외래키 처리 확인--alter-foreign-keys-method 사전 점검
mvn flyway:migrateFlyway 마이그레이션 반영mvn flyway:info (Pending/Success 확인)
mvn flyway:repair실패·체크섬 불일치 이력 복구실패 마이그레이션 정리 후 재적용
SELECT … flyway_schema_history환경별 반영 버전 추적ORDER BY installed_rank DESC LIMIT 5
KILL <세션ID>metadata lock 유발 세션 종료블로킹 세션 확인 후 KILL 12345

관련 모듈로 더 깊이:

다음 모듈에서는 이렇게 DB까지 준비된 상태에서 애플리케이션을 배포하는 전체 배포 구조와 스크립트를 다룹니다.

지식 확인

퀴즈 — 8문제

Q1

운영 DB에 DDL을 적용하기 전 반드시 해야 할 것으로 올바른 것은?

Q2

대용량 테이블에 ALTER TABLE로 컬럼을 추가할 때 Lock이 발생하는 이유는?

Q3

개발, 스테이징, 운영 3개 환경 DB 스키마가 서로 달라져 '개발에선 되는데 운영에선 안 된다'는 문제가 반복됩니다. 환경 간 스키마 불일치를 자동으로 관리하는 도구로 팀이 도입하기로 했습니다. Flyway를 선택했을 때 얻을 수 있는 것은?

Q4

TRUNCATE와 DELETE의 차이에서 운영 환경에서 특히 주의해야 하는 점은?

Q5

수천만 행 테이블에 컬럼을 추가해야 하는데 ALTER TABLE이 테이블을 장시간 Lock한다. pt-online-schema-change 같은 온라인 DDL 도구가 무중단으로 처리하는 원리는?

Q6

Flyway로 마이그레이션을 관리할 때, 이미 운영에 적용된 V2__add_column.sql 파일을 나중에 수정하면 어떻게 되나?

Q7

[심화] pt-online-schema-change가 shadow 테이블 + 트리거로 무중단에 가깝게 스키마를 바꿔 주지만, 그 대가로 대용량 테이블에서 여전히 준비해야 하는 것은?

Q8

[심화] orders 테이블에 pt-osc로 컬럼을 추가했더니, orders를 외래키로 참조하는 대용량 order_items 때문에 작업이 몇 시간째 끝나지 않고 복제 지연이 치솟습니다. 원인을 확정하는 진단으로 가장 적절한 것은?

0 / 8 답변

🧪 실습으로 확인하기

Nginx 설치 및 기동

초급

Linux 서버에 Nginx를 설치하고 systemd 서비스로 등록하여 80포트에서 응답하는 상태까지 만든다.

40📋 3단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요