카테고리 : MySQL/기술노트

Consistent backup과 transaction: mysqldump --single-transaction의 의미

mysqldump --single-transaction이 InnoDB의 일관된 스냅샷을 만드는 원리와 적용 범위, DDL 위험, 운영 검증 절차를 정리한다.

저자: MySQL 기술 노트 작성: 2026.08.10 약 11분 6,552자
다운로드

mysqldump --single-transaction은 서비스 쓰기를 장시간 차단하지 않고 InnoDB 데이터를 논리 백업할 때 널리 사용하는 옵션이다. 그러나 이 옵션을 “덤프 전체를 하나의 원자적 파일로 만든다”거나 “모든 객체를 같은 시점으로 고정한다”는 뜻으로 이해하면 복구 시점에 예상하지 못한 불일치가 드러날 수 있다.

핵심은 더 제한적이고 명확하다. mysqldump 세션이 REPEATABLE READ의 consistent snapshot을 열고, 그 Read View에서 InnoDB 행을 읽는 것이다. 따라서 트랜잭션 테이블의 커밋된 행 버전에는 일관성이 있지만, MyISAM 같은 비트랜잭션 테이블, 실행 중인 DDL, 서버 외부 객체, 복구 단계의 원자성까지 자동으로 보장하지는 않는다.

이 글에서는 옵션의 내부 동작, 일관성 경계, 운영 중 실패 조건, Aurora MySQL에서의 해석, 실제 백업·복구 점검 절차를 차례로 설명한다.

1. 옵션이 만드는 일관성의 경계

일관된 백업을 판단할 때는 먼저 무엇이 같은 시점이어야 하는지 구분해야 한다.

대상 --single-transaction의 기본 보장 운영 해석
InnoDB 행 데이터 같은 consistent snapshot에서 읽음 덤프 도중 커밋된 변경은 해당 스냅샷에 보이지 않음
InnoDB 테이블 정의 행 버전과 같은 방식의 MVCC 대상이 아님 DDL 동결 또는 별도 통제가 필요함
MyISAM 등 비트랜잭션 테이블 consistent snapshot 미적용 쓰기 정지나 명시적 잠금 없이는 시점 일관성이 없음
View, Trigger, Routine, Event 옵션과 권한에 따라 추출하지만 하나의 행 Read View로 원자화되지 않음 배포 변경을 백업 창과 겹치지 않게 해야 함
사용자·권한·서버 설정 일반 애플리케이션 DB 덤프만으로 완전하지 않음 별도 백업·형상 관리 범위를 정의해야 함
출력 파일 복구 복구 전체가 자동으로 한 트랜잭션이 되지 않음 격리된 복구 대상과 검증·전환 절차가 필요함

즉, 이 옵션은 InnoDB 행 데이터의 논리적 시점 일관성을 해결한다. 백업 시스템 전체의 모든 문제를 해결하는 옵션은 아니다.

2. 내부 동작: Read View와 undo가 백업을 지탱한다

mysqldump--single-transaction을 사용할 때 트랜잭션 격리 수준을 REPEATABLE READ로 설정하고 consistent snapshot을 시작한다. 이후 각 테이블을 차례로 읽더라도 InnoDB는 같은 Read View 기준으로 가시성을 판정한다.

sequenceDiagram
    participant D as mysqldump 세션
    participant I as InnoDB
    participant A as 애플리케이션 세션
    participant U as Undo/Purge

    D->>I: REPEATABLE READ 설정
    D->>I: START TRANSACTION WITH CONSISTENT SNAPSHOT
    I-->>D: Read View 생성
    D->>I: orders 읽기
    A->>I: orders UPDATE 후 COMMIT
    I->>U: 이전 행 버전을 undo로 보존
    D->>I: customers와 나머지 테이블 읽기
    I-->>D: 같은 Read View에 맞는 행 버전 반환
    D->>I: COMMIT
    I->>U: 오래된 Read View 해제 후 purge 가능

스냅샷이 생성된 뒤 다른 세션이 행을 수정하고 커밋해도 덤프 세션에는 새 버전이 보이지 않는다. InnoDB는 undo 정보를 따라 스냅샷 시점에 가시적이었던 이전 버전을 재구성한다. 이 특성 덕분에 애플리케이션의 일반적인 INSERT, UPDATE, DELETE를 막지 않고 백업할 수 있다.

반대급부도 있다. 대용량 덤프가 오래 실행되면 오래된 Read View 때문에 purge가 제거하고 싶어도 제거할 수 없는 행 버전이 늘 수 있다. 그 결과 undo 보존량, History list length, 버퍼와 스토리지 I/O 부담이 증가할 수 있다. --single-transaction은 잠금을 없애는 옵션이라기보다 행 잠금 대신 장수 스냅샷의 비용을 선택하는 옵션에 가깝다.

2.1 대상 환경 확인

백업 전에 서버 버전과 세션 격리 수준을 확인한다. 다음 SQL은 MySQL 8.0 계열에서 사용할 수 있다.

SELECT VERSION() AS mysql_version,
       @@session.transaction_isolation AS session_isolation,
       @@session.autocommit AS autocommit;

실행 결과(MySQL 8.0.x):

mysql> SELECT VERSION() AS mysql_version,
    ->        @@session.transaction_isolation AS session_isolation,
    ->        @@session.autocommit AS autocommit;

+---------------+-------------------+------------+
| mysql_version | session_isolation | autocommit |
+---------------+-------------------+------------+
| 8.0.46        | REPEATABLE-READ   |          1 |
+---------------+-------------------+------------+
1 row in set (0.00 sec)

mysqldump가 자체 세션 설정을 수행하므로, 애플리케이션의 기본 격리 수준이 다르더라도 옵션의 의미가 바로 사라지지는 않는다. 다만 프록시가 세션 명령을 제한하거나, 관리형 서비스의 권한 정책이 일부 명령을 막는 환경에서는 실제 백업 로그를 확인해야 한다.

2.2 같은 스냅샷이 유지되는지 재현하기

다음 예제는 Event Scheduler를 별도 서버 세션으로 사용한다. 백업 역할의 트랜잭션이 100을 읽은 뒤, 다른 세션이 값을 200으로 바꾼다. 스냅샷 안에서는 계속 100이 보이고, 커밋 뒤에는 200이 보이는지 확인한다.

SET NAMES utf8mb4;
SET GLOBAL event_scheduler = ON;

DROP TABLE IF EXISTS tech_note_snapshot;
CREATE TABLE tech_note_snapshot (
    id BIGINT NOT NULL PRIMARY KEY,
    amount INT NOT NULL
) ENGINE=InnoDB;
INSERT INTO tech_note_snapshot VALUES (1, 100);

DROP EVENT IF EXISTS tech_note_snapshot_change;
CREATE EVENT tech_note_snapshot_change
    ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND
    ON COMPLETION NOT PRESERVE
    DO UPDATE tech_note_snapshot SET amount = 200 WHERE id = 1;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT '스냅샷 시작' AS phase, amount
FROM tech_note_snapshot WHERE id = 1;
DO SLEEP(3);
SELECT '다른 세션 커밋 후에도 같은 스냅샷' AS phase, amount
FROM tech_note_snapshot WHERE id = 1;
COMMIT;
SELECT '스냅샷 종료 후 현재 값' AS phase, amount
FROM tech_note_snapshot WHERE id = 1;

DROP TABLE tech_note_snapshot;

실행 결과(MySQL 8.0.x):

준비·정리 DDL과 반복되는 성공 메시지는 일부 줄였으며, 스냅샷 가시성을 보여 주는 핵심 결과는 실제 검증값이다.

mysql> CREATE TABLE tech_note_snapshot (...) ENGINE=InnoDB;
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tech_note_snapshot VALUES (1, 100);
Query OK, 1 row affected (0.01 sec)

mysql> START TRANSACTION WITH CONSISTENT SNAPSHOT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT '스냅샷 시작' AS phase, amount
    -> FROM tech_note_snapshot WHERE id = 1;
+------------------+--------+
| phase            | amount |
+------------------+--------+
| 스냅샷 시작      |    100 |
+------------------+--------+
1 row in set (0.00 sec)

mysql> DO SLEEP(3);
Query OK, 0 rows affected (3.00 sec)

mysql> SELECT '다른 세션 커밋 후에도 같은 스냅샷' AS phase, amount
    -> FROM tech_note_snapshot WHERE id = 1;
+------------------------------------------+--------+
| phase                                    | amount |
+------------------------------------------+--------+
| 다른 세션 커밋 후에도 같은 스냅샷       |    100 |
+------------------------------------------+--------+
1 row in set (0.00 sec)

mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT '스냅샷 종료 후 현재 값' AS phase, amount
    -> FROM tech_note_snapshot WHERE id = 1;
+----------------------------+--------+
| phase                      | amount |
+----------------------------+--------+
| 스냅샷 종료 후 현재 값     |    200 |
+----------------------------+--------+
1 row in set (0.00 sec)

이 재현은 mysqldump 프로그램 전체를 흉내 내는 것이 아니라, --single-transaction의 핵심 기반인 InnoDB consistent snapshot의 가시성만 검증한다.

3. --quick, 잠금 옵션과 함께 해석하기

대용량 논리 백업에서는 보통 다음과 같이 실행한다.

mysqldump \
  --host=db.example.invalid \
  --user=backup_operator \
  --password \
  --single-transaction \
  --quick \
  --routines \
  --events \
  --triggers \
  --hex-blob \
  --set-gtid-purged=OFF \
  --databases appdb > appdb-2026-08-10.sql

--password 뒤에 값을 적지 않으면 client가 대화형으로 암호를 묻는다. 자동화에서는 명령행 인자에 평문 암호를 넣지 말고, 권한을 제한한 option file이나 운영 환경의 secret 주입 방식을 사용한다.

--quick은 결과 전체를 client 메모리에 모은 뒤 출력하지 않고 row를 순차적으로 가져오도록 한다. --opt에 기본 포함되지만, 실행 명령에서 명시하면 대용량 덤프의 의도를 더 분명히 남길 수 있다. 반면 --single-transaction--lock-tables를 끈다. 두 옵션을 함께 적어 잠금과 스냅샷을 동시에 얻는다고 생각해서는 안 된다. 나중에 적은 상충 옵션이나 wrapper가 추가한 옵션 때문에 동작이 달라질 수 있으므로 실제 명령과 mysqldump --help를 함께 보관하는 편이 안전하다.

3.1 복제 좌표가 필요할 때

시점 복구나 새 replica 초기화에 binary log 좌표가 필요하면 --source-data=2를 검토한다. 이 옵션은 덤프에 복제 시작 정보를 주석 형태로 기록한다. 다만 consistent snapshot과 좌표를 맞추기 위한 시작 단계에서 짧은 global read lock이 필요할 수 있으며, 계정에도 추가 권한이 요구될 수 있다.

GTID 환경에서는 --set-gtid-purged=AUTO|ON|OFF의 선택이 복구 대상의 기존 GTID 상태에 영향을 준다. 단순히 “백업이 성공했다”는 이유로 안전한 값이 결정되지는 않는다. 다음을 먼저 정해야 한다.

  • 빈 인스턴스에 전체 이관하는가, 기존 GTID 이력이 있는 서버에 일부 DB만 넣는가
  • 이 덤프를 replica 초기화에 사용하는가
  • 복구 뒤 binary logging이 켜진 상태에서 다시 실행되는가
  • dump 파일에 SET @@GLOBAL.GTID_PURGED가 포함되어도 되는가

부분 논리 백업에서는 OFF가 충돌을 줄일 수 있지만, 복제 계보 복원이 목적이라면 필요한 GTID 정보를 잃을 수 있다. 선택 근거를 백업 runbook에 기록해야 한다.

4. 트랜잭션 테이블만 같은 시점으로 보인다

다음 SQL은 동일한 스키마에도 서로 다른 storage engine이 섞일 수 있음을 확인한다.

DROP TABLE IF EXISTS tech_note_innodb;
DROP TABLE IF EXISTS tech_note_myisam;

CREATE TABLE tech_note_innodb (
    id INT NOT NULL PRIMARY KEY,
    value_text VARCHAR(30) NOT NULL
) ENGINE=InnoDB;

CREATE TABLE tech_note_myisam (
    id INT NOT NULL PRIMARY KEY,
    value_text VARCHAR(30) NOT NULL
) ENGINE=MyISAM;

SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME IN ('tech_note_innodb', 'tech_note_myisam')
ORDER BY TABLE_NAME;

DROP TABLE tech_note_myisam;
DROP TABLE tech_note_innodb;

실행 결과(MySQL 8.0.x):

mysql> DROP TABLE IF EXISTS tech_note_innodb;

Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE IF EXISTS tech_note_myisam;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE tech_note_innodb (
    ->     id INT NOT NULL PRIMARY KEY,
    ->     value_text VARCHAR(30) NOT NULL
    -> ) ENGINE=InnoDB;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE tech_note_myisam (
    ->     id INT NOT NULL PRIMARY KEY,
    ->     value_text VARCHAR(30) NOT NULL
    -> ) ENGINE=MyISAM;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT TABLE_NAME, ENGINE
    -> FROM information_schema.TABLES
    -> WHERE TABLE_SCHEMA = DATABASE()
    ->   AND TABLE_NAME IN ('tech_note_innodb', 'tech_note_myisam')
    -> ORDER BY TABLE_NAME;

+------------------+--------+
| TABLE_NAME       | ENGINE |
+------------------+--------+
| tech_note_innodb | InnoDB |
| tech_note_myisam | MyISAM |
+------------------+--------+
2 rows in set (0.00 sec)

mysql> DROP TABLE tech_note_myisam;

Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE tech_note_innodb;

Query OK, 0 rows affected (0.00 sec)

MyISAM은 MVCC consistent snapshot에 참여하지 않는다. 덤프가 여러 MyISAM 테이블을 순서대로 읽는 동안 쓰기가 계속되면, 각 테이블이 서로 다른 업무 시점을 나타낼 수 있다. InnoDB와 MyISAM을 조인하는 데이터 관계도 깨질 수 있다.

운영 환경에서는 다음과 같이 engine 분포를 먼저 조사한다.

SELECT TABLE_SCHEMA, ENGINE, COUNT(*) AS table_count
FROM information_schema.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
  AND TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
GROUP BY TABLE_SCHEMA, ENGINE
ORDER BY TABLE_SCHEMA, ENGINE;

위 문장은 실제 운영 스키마를 대상으로 범위를 정한 뒤 실행해야 하므로 재현용 SQL fence가 아닌 점검 템플릿으로 제시했다. 비트랜잭션 테이블이 있다면 다음 중 하나를 명시적으로 선택한다.

  1. 백업 창 동안 해당 테이블의 쓰기를 중지한다.
  2. 서비스 영향도를 검토한 뒤 read lock 기반 백업을 사용한다.
  3. 테이블을 InnoDB로 전환한다.
  4. 물리 snapshot이나 다른 백업 도구로 일관성 요구를 충족한다.

5. DDL은 왜 위험한가

MVCC는 행 버전을 다루지만, 테이블 정의 변경을 덤프 전체 기간의 단일 스냅샷으로 고정하지는 않는다. 백업 중 ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE이 실행되면 다음 문제가 생길 수 있다.

  • 덤프 초기에 읽은 table definition과 나중에 읽는 행 구조가 달라진다.
  • 아직 읽지 않은 테이블이 rename 또는 drop되어 덤프가 실패한다.
  • 행 데이터는 이전 시점인데 trigger, view, routine 정의는 이후 배포 상태가 된다.
  • schema migration이 여러 테이블을 순서대로 바꾸면 파일 내부 객체들이 서로 다른 migration 단계에 놓인다.

MySQL의 metadata lock(MDL)은 DDL과 동시 접근을 조정한다. 일반적으로 트랜잭션 안에서 읽은 테이블에는 트랜잭션 수명의 metadata lock이 남을 수 있다.

DROP TABLE IF EXISTS tech_note_mdl;
CREATE TABLE tech_note_mdl (
    id INT NOT NULL PRIMARY KEY,
    note_text VARCHAR(50) NOT NULL
) ENGINE=InnoDB;
INSERT INTO tech_note_mdl VALUES (1, 'consistent backup');

START TRANSACTION WITH CONSISTENT SNAPSHOT;
SELECT * FROM tech_note_mdl;
SELECT OBJECT_TYPE,
       OBJECT_SCHEMA,
       OBJECT_NAME,
       LOCK_TYPE,
       LOCK_DURATION,
       LOCK_STATUS
FROM performance_schema.metadata_locks
WHERE OWNER_THREAD_ID = PS_CURRENT_THREAD_ID()
  AND OBJECT_SCHEMA = DATABASE()
  AND OBJECT_NAME = 'tech_note_mdl';
COMMIT;

DROP TABLE tech_note_mdl;

실행 결과(MySQL 8.0.x):

mysql> DROP TABLE IF EXISTS tech_note_mdl;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE tech_note_mdl (
    ->     id INT NOT NULL PRIMARY KEY,
    ->     note_text VARCHAR(50) NOT NULL
    -> ) ENGINE=InnoDB;

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO tech_note_mdl VALUES (1, 'consistent backup');

Query OK, 1 row affected (0.00 sec)

mysql> START TRANSACTION WITH CONSISTENT SNAPSHOT;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tech_note_mdl;

+----+-------------------+
| id | note_text         |
+----+-------------------+
|  1 | consistent backup |
+----+-------------------+
1 row in set (0.00 sec)

mysql> SELECT OBJECT_TYPE,
    ->        OBJECT_SCHEMA,
    ->        OBJECT_NAME,
    ->        LOCK_TYPE,
    ->        LOCK_DURATION,
    ->        LOCK_STATUS
    -> FROM performance_schema.metadata_locks
    -> WHERE OWNER_THREAD_ID = PS_CURRENT_THREAD_ID()
    ->   AND OBJECT_SCHEMA = DATABASE()
    ->   AND OBJECT_NAME = 'tech_note_mdl';

+-------------+-----------------+---------------+-------------+---------------+-------------+
| OBJECT_TYPE | OBJECT_SCHEMA   | OBJECT_NAME   | LOCK_TYPE   | LOCK_DURATION | LOCK_STATUS |
+-------------+-----------------+---------------+-------------+---------------+-------------+
| TABLE       | mysql_tech_note | tech_note_mdl | SHARED_READ | TRANSACTION   | GRANTED     |
+-------------+-----------------+---------------+-------------+---------------+-------------+
1 row in set (0.01 sec)

mysql> COMMIT;

Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE tech_note_mdl;

Query OK, 0 rows affected (0.00 sec)

그러나 이 사실만으로 전체 덤프가 DDL로부터 보호된다고 볼 수 없다. 아직 접근하지 않은 테이블의 DDL은 먼저 진행될 수 있고, 이미 접근한 테이블의 DDL은 덤프 종료까지 기다리며 deployment timeout이나 metadata lock 대기열을 만들 수 있다. 안전한 원칙은 논리 백업 시간에 schema migration을 중지하는 것이다.

배포 중단이 불가능하면 백업과 migration의 순서를 오케스트레이션하고, performance_schema.metadata_locks와 장기 트랜잭션을 함께 감시해야 한다. DDL이 기다리는 동안 뒤따르는 쿼리까지 대기하는 MDL queue가 생길 수 있으므로, “쓰기 DML이 계속 성공한다”는 사실만으로 서비스 영향이 없다고 판단하면 안 된다.

6. 성능과 장애 모드

6.1 오래된 Read View와 purge 지연

덤프가 수시간 지속되는 동안 변경량이 많으면 undo가 빠르게 누적될 수 있다. 논리 백업 자체의 SELECT 부하뿐 아니라 이전 행 버전 보존 비용도 고려해야 한다. 다음 지표를 같은 시간축으로 관찰한다.

  • 덤프 처리량과 예상 완료 시간
  • information_schema.INNODB_METRICStrx_rseg_history_len
  • undo tablespace 사용량과 스토리지 증가율
  • buffer pool read, 데이터 파일 I/O, redo 생성량
  • 애플리케이션 쿼리 지연 시간과 replica lag
  • information_schema.INNODB_TRX의 장기 실행 트랜잭션

History list length는 변경량, purge 처리량, 다른 장기 트랜잭션의 존재에 좌우된다. 특정 임계값 하나만으로 장애를 선언하기보다 증가 기울기와 백업 종료 후 회복 여부를 본다.

6.2 client·network·파일 시스템 실패

논리 덤프는 DB 읽기 외에도 client 프로세스, 네트워크, stdout redirection, 로컬 파일 시스템에 의존한다. 다음과 같은 실패는 MySQL 서버의 백업 트랜잭션이 정상이어도 파일을 불완전하게 만든다.

  • SSH나 네트워크 연결 종료
  • max_allowed_packet 부족으로 큰 행 전송 실패
  • 대상 디스크 용량 또는 inode 고갈
  • shell pipeline 중간 압축 프로세스 실패를 놓침
  • client가 종료되었는데 wrapper가 exit code를 확인하지 않음
  • 파일은 생성되었지만 마지막 객체와 dump completion marker가 없음

압축 pipeline을 사용한다면 set -o pipefail과 각 단계의 종료 상태를 확인한다. 파일 존재 여부나 크기 증가만으로 성공을 판정하지 않는다.

set -o pipefail
mysqldump --single-transaction --quick --databases appdb \
  | gzip -1 > appdb-2026-08-10.sql.gz
status=$?
test "$status" -eq 0

6.3 복구는 별도의 검증 대상이다

덤프 파일은 백업 결과물이지 복구 성공의 증명이 아니다. CREATE TABLE, ALTER TABLE, INSERT가 연속 실행되는 restore는 전체가 한 트랜잭션으로 되돌려지는 작업이 아니다. 중간 실패 시 일부 객체만 생성될 수 있다.

따라서 운영 DB 위에 바로 덮어쓰기보다 격리된 인스턴스에 복원한다.

mysql --host=restore.example.invalid --user=restore_operator --password \
  < appdb-2026-08-10.sql

복원 후에는 최소한 다음을 확인한다.

  • 예상 schema, table, view, trigger, routine, event의 존재
  • 핵심 테이블 row count와 업무 불변식
  • foreign key와 unique key 위반 여부
  • 문자셋·collation·time zone 차이
  • 애플리케이션 smoke test
  • 백업 파일 checksum과 보존 위치
  • 목표 RTO 안에서 restore가 끝나는지

7. Aurora MySQL에서의 운영 해석

Aurora MySQL에서도 논리 조회의 consistent snapshot이라는 기본 원리는 유효하다. 다만 전체 클러스터 복구의 주력 수단과 이식 가능한 논리 추출의 역할을 구분해야 한다.

  • 전체 클러스터 복구와 시점 복구에는 Aurora의 automated backup, snapshot, point-in-time restore가 일반적으로 더 빠르고 운영 친화적이다.
  • 일부 스키마 이관, 버전 간 논리 이동, 객체 단위 검토, 다른 MySQL 환경으로의 이동에는 mysqldump가 여전히 유용하다.
  • reader endpoint에서 실행하면 writer의 직접 CPU 부담을 줄일 수 있지만, 선택된 reader의 부하와 복제 지연, 장수 snapshot의 비용을 관찰해야 한다.
  • reader가 장애 조치나 재시작으로 교체되면 장시간 dump 연결이 끊길 수 있다. endpoint 사용만으로 dump 재개 가능성이 생기는 것은 아니다.
  • parameter group, cluster 설정, 사용자와 권한, 외부 secret, 네트워크 설정은 애플리케이션 schema dump만으로 복구되지 않는다.

Aurora snapshot이 있다고 해서 논리 복구 테스트가 불필요한 것도 아니고, 논리 덤프가 있다고 해서 cluster snapshot이 불필요한 것도 아니다. 두 방식은 복구 단위와 속도, 이식성, 운영 비용이 다르므로 계층적으로 구성하는 편이 안전하다.

8. 운영 실행 절차

백업 전

  • schema migration과 TRUNCATE

백업 중

  • mysqldump
  • 장기 트랜잭션, undo 증가율, History list length

백업 후

9. 선택 기준 요약

다음 조건이라면 --single-transaction --quick이 적합한 출발점이다.

  • 대상이 사실상 InnoDB로 구성되어 있다.
  • 일반 DML을 중단하기 어렵지만 DDL 배포는 통제할 수 있다.
  • 객체 또는 schema 단위의 이식 가능한 논리 백업이 필요하다.
  • 장수 snapshot의 undo·I/O 비용을 감시할 수 있다.
  • 복구 테스트를 별도 환경에서 정기적으로 수행한다.

반대로 비트랜잭션 테이블이 중요하거나, DDL이 계속 발생하거나, 전체 인스턴스를 짧은 RTO로 복원해야 한다면 이 옵션 하나로 요구사항을 충족시키려 해서는 안 된다. 쓰기 정지, 잠금 기반 백업, 물리 백업, 스토리지 snapshot, 관리형 서비스의 시점 복구를 조합해야 한다.

맺음말

mysqldump --single-transaction의 본질은 “무잠금 백업”이라는 구호가 아니라, InnoDB MVCC의 Read View와 undo를 이용해 트랜잭션 테이블의 행을 한 논리 시점으로 읽는 것이다. 이 경계를 정확히 알면 DML은 허용하되 DDL은 통제하고, 비트랜잭션 테이블은 별도 처리하며, 장기 snapshot의 비용을 감시하는 운영 설계를 만들 수 있다.

다음 단계에서는 논리 백업 파일의 구성 요소와 restore 순서, GTID·binary log 좌표를 이용한 시점 복구 연결, 그리고 실제 복구 리허설에서 확인해야 할 데이터 불변식을 더 구체적으로 다룰 수 있다.