---
title: "Consistent backup과 transaction: mysqldump --single-transaction의 의미"
description: "mysqldump --single-transaction이 InnoDB의 일관된 스냅샷을 만드는 원리와 적용 범위, DDL 위험, 운영 검증 절차를 정리한다."
tags: [ MySQL, 백업복구, 트랜잭션, 운영, DBA ]
image: "mysql-report-bg.png"
published: "2026-08-10"
updated: "2026-08-10"
author: "MySQL 기술 노트"
source_url: ""
---

`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 기준으로 가시성을 판정한다.

```mermaid
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 계열에서 사용할 수 있다.

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

실행 결과(MySQL 8.0.x):

```text
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`이 보이는지 확인한다.

```sql
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과 반복되는 성공 메시지는 일부 줄였으며, 스냅샷 가시성을 보여 주는 핵심 결과는 실제 검증값이다.

```text
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`, 잠금 옵션과 함께 해석하기

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

```bash
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이 섞일 수 있음을 확인한다.

```sql
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):

```text
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 분포를 먼저 조사한다.

```text
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이 남을 수 있다.

```sql
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):

```text
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_METRICS`의 `trx_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`과 각 단계의 종료 상태를 확인한다. 파일 존재 여부나 크기 증가만으로 성공을 판정하지 않는다.

```bash
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 위에 바로 덮어쓰기보다 격리된 인스턴스에 복원한다.

```bash
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. 운영 실행 절차

### 백업 전

- [ ] 백업 대상 DB와 제외 대상을 명시했다.
- [ ] 모든 base table의 storage engine을 확인했다.
- [ ] backup account에 필요한 최소 권한을 부여했다.
- [ ] schema migration과 `TRUNCATE` 작업을 백업 창에서 차단했다.
- [ ] 예상 데이터량, 출력 파일 크기, 여유 디스크, 완료 시간을 산정했다.
- [ ] GTID와 binary log 좌표 포함 정책을 결정했다.
- [ ] routine, event, trigger 포함 여부를 명시했다.
- [ ] 장기 snapshot과 purge 지연을 관찰할 지표를 준비했다.

### 백업 중

- [ ] `mysqldump`와 pipeline의 exit code를 수집한다.
- [ ] 출력 파일 크기와 파일 시스템 여유 공간을 감시한다.
- [ ] 장기 트랜잭션, undo 증가율, `History list length`를 관찰한다.
- [ ] DDL 배포가 시작되지 않았는지 확인한다.
- [ ] DB CPU·I/O, 응답 시간, replica lag를 함께 본다.
- [ ] MDL 대기와 DDL 대기열을 확인한다.

### 백업 후

- [ ] dump 종료가 정상인지 로그와 종료 코드로 확인한다.
- [ ] checksum을 계산하고 백업 파일과 별도로 기록한다.
- [ ] 암호화·접근 제어·retention 정책을 적용한다.
- [ ] 격리된 환경에서 실제 restore를 수행한다.
- [ ] schema 객체와 핵심 데이터 불변식을 검증한다.
- [ ] restore 소요 시간이 RTO를 충족하는지 기록한다.
- [ ] 복구 파일을 사용한 전환·rollback 절차를 연습한다.

## 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 좌표를 이용한 시점 복구 연결, 그리고 실제 복구 리허설에서 확인해야 할 데이터 불변식을 더 구체적으로 다룰 수 있다.
