『MySQLのバックアップと復旧完全ガイド』
アリスの会社のサーバーのハードドライブが突然故障し、データベースが完全にダウンしてしまいました。バックアップがなかったため、3年分の顧客データ、注文記録、財務情報が永久に失われてしまった。この大惨事は彼女にとって警鐘となり、包括的なバックアップシステムの構築へとつながった。具体的には、毎日のmysqldumpによるフルバックアップ、継続的な増分binlogバックアップ、週1回のオフサイトへのデータ転送、そして月1回の復旧訓練である。それ以来、たとえ再びハードウェア障害が発生したとしても、彼女は30分以内にすべてのデータを完全に復元できるようになった。
このレッスンでは、次のことを学びます:
- mysqldump の論理バックアップの 5 つのモード(フル/単一データベース/単一テーブル/構造のみ/データのみ)
- MySQL コマンドと SOURCE 文を使用した復元方法
- SELECT INTO OUTFILE によるエクスポートと、LOAD DATA INFILE によるインポート
- バイナリログ(binlog)およびポイント・イン・タイム・リカバリ(PITR)の全プロセス
- XtraBackup:物理バックアップの原則とバックアップ戦略の策定
flowchart TD
A[Daily Full Backup<br/>mysqldump --single-transaction] --> B[binlog Ongoing Record<br/>Real-Time Incremental]
B --> C[Weekly Remote Data Transfer<br/>rsync/scp To Remote]
C --> D[Monthly Recovery Drills<br/>Verify Backup Availability]
D -->|Drill Passed| A
D -->|Identifying Problems| E[Adjust the Backup Strategy]
E --> A
1. ストーリー:バックアップがないことの代償
アリスが勤務するTechFlow社は、eコマースプラットフォーム用にMySQLデータベースを運用しており、そこには3年分の顧客注文情報やアカウント情報が保存されていた。運用チームはこれまで正式なバックアップ手順を確立しておらず、RAIDアレイのみを「安全策」として頼りにしていた。ある金曜日の夜、データセンターの空調システムの故障によりサーバーが過熱し、その結果、2台のハードドライブが同時に故障し、RAIDアレイが崩壊してしまった。顧客情報、取引記録、在庫データなど、すべてのデータが失われてしまいました。同社は3か月間にわたりデータ復旧を試みましたが、回復できたデータは10%未満にとどまりました。直接的な経済的損失は50万米ドルを超え、同社は顧客からの信頼も大きく失うこととなりました。
この痛ましい教訓を経て、アリスは率先して包括的なバックアップ体制を構築しました。具体的には、毎日深夜0時に自動で実行されるフルバックアップ、binlogを利用したリアルタイムの増分バックアップ、週1回のオフサイト同期、そして月1回の復旧訓練です。6か月後、サーバーは再び障害を起こしましたが、今回は彼女が30分以内に完全な復旧を完了させ、業務の中断は事実上ありませんでした。
2. 論理バックアップと物理バックアップ
(1) 論理バックアップの概要
論理バックアップでは、データベースからデータをエクスポートし、CREATE TABLE や INSERT といったステートメントを含む SQL テキストファイルとして保存します。データを復元するには、これらの SQL ステートメントを再実行するだけで済みます。代表的なツールとして mysqldump が挙げられます。
利点: 高い可読性、バージョン間の互換性、および個々のデータベースやテーブルを選択的にバックアップできる機能。
デメリット: 処理速度が遅い;バックアップと復元の両方にMySQLプロセスの関与が必要;大規模なデータベースでは時間がかかる。
(2) 物理バックアップの概要
物理バックアップでは、データベースの基盤となるデータファイル(.ibd、.frm など)が直接コピーされます。復元するには、これらのファイルをデータディレクトリにコピーし直すだけで済みます。代表的なツールとして XtraBackup が挙げられます。
利点: 高速、テーブルロックなし(InnoDB)、大規模なデータベースに適している。
デメリット: 人間が読み取れないこと、クロスプラットフォームの互換性が限られていること、そして一貫性を維持するためにダウンタイムが必要になるか、専用のツールを使用する必要があること。
| 比較項目 | 論理バックアップ (mysqldump) | 物理バックアップ (XtraBackup) |
|---|---|---|
| バックアップ対象 | SQL文 | データファイルのコピー |
| バックアップ速度 | 遅い(行単位のエクスポート) | 速い(ファイルコピー) |
| 復旧速度 | 遅い(SQLを1行ずつ実行する) | 速い(ファイルをコピーして復元する) |
| テーブルロックの影響 | InnoDBのロックフリー | テーブルロックなし |
| 可読性 | 高 (プレーンテキストのSQL) | 低 (バイナリファイル) |
| ストレージのオーバーヘッド | 低(テキストの圧縮率が高い) | 高(ファイルの完全コピー) |
| バージョン間 | 互換性あり | バージョンの一致が必要 |
| ユースケース | 50 GB以下の中小規模データベース | 50 GBを超える大規模データベース |
3. mysqldump による論理バックアップの詳細な解説
(1) 完全バックアップ
フルバックアップでは、すべてのデータベースからすべてのデータがエクスポートされます。これは、最も基本的かつ安全なバックアップ方法です。
mysqldump -u root -p --all-databases --single-transaction > full_backup.sql
--single-transaction パラメータは、InnoDB テーブルの読み取り処理において一貫性スナップショットを使用し、テーブルをロックしません。MyISAM テーブルは引き続きロックされます。
(2) 単一データベースおよび単一テーブルのバックアップ
# Backing Up a Single Database
mysqldump -u root -p --single-transaction mydb > mydb_backup.sql
# Back up the specified table
mysqldump -u root -p --single-transaction mydb users orders > tables_backup.sql
(3) 構造とデータの分離
# Back up only the table structure
mysqldump -u root -p --no-data mydb > mydb_schema.sql
# Back up only the data
mysqldump -u root -p --no-create-info mydb > mydb_data.sql
▶ 例:mysqldump の 5 つのバックアップモード
# Pattern1:Full Backup(All Libraries)
mysqldump -u root -p --all-databases \
--single-transaction --routines --triggers \
> full_backup_$(date +%Y%m%d).sql
# Pattern2:Single-Database Backup
mysqldump -u root -p --single-transaction mydb > mydb.sql
# Pattern3:Single-Table Backup
mysqldump -u root -p --single-transaction mydb users > users.sql
# Pattern4:Structure Only
mysqldump -u root -p --no-data mydb > schema.sql
# Pattern5:Data Only
mysqldump -u root -p --no-create-info mydb > data.sql
| パラメータ | 機能 | ユースケース |
|---|---|---|
--all-databases |
すべてのデータベースをバックアップ | 完全バックアップ |
--single-transaction |
InnoDB 一貫性スナップショット | テーブルロックを伴わないオンラインバックアップ |
--no-data |
テーブル構造のみをエクスポート | ドキュメント、データベース作成スクリプト |
--no-create-info |
データのエクスポートのみ | データ移行 |
--routines |
ストアドプロシージャおよび関数を含む | 完全論理バックアップ |
--triggers |
トリガー機能付き | ロジック全体のバックアップ |
--where="condition" |
条件に基づいて選択した行をエクスポート | データの一部移行 |
--quick |
キャッシュせずに1行ずつ読み込む | 大規模なテーブルのバックアップ中のOOMを防ぐ |
4. データベースの復元
(1) MySQL コマンドによる復旧
バックアップされたSQLファイルから、指定したデータベースにデータを復元する:
mysql -u root -p mydb < mydb_backup.sql
圧縮されたバックアップファイルを復元する:
gunzip < mydb_backup.sql.gz | mysql -u root -p mydb
(2) SOURCE コマンドによる復元
MySQL クライアント内の SOURCE コマンドを使用して復元します:
USE mydb;
SOURCE /var/backups/mysql/mydb_backup.sql;
▶ 例:復旧プロセス
# Steps1:Create the target database
mysql -u root -p -e "CREATE DATABASE mydb_restore;"
# Steps2:Restore Data
mysql -u root -p mydb_restore < mydb_backup.sql
# Steps3:Number of rows to verify
mysql -u root -p -e "SELECT COUNT(*) FROM mydb_restore.users;"
▶ 例:圧縮バックアップの復元
# Restore gzip Compressed Backup
gunzip < /backup/mydb_20260703.sql.gz | mysql -u root -p mydb
# Restore and display progress
pv /backup/mydb_20260703.sql.gz | gunzip | mysql -u root -p mydb
5. データのエクスポートとインポート
(1) SELECT INTO OUTFILE
クエリの結果をサーバー側のCSVファイルにエクスポートします:
SELECT id, name, email
FROM users
WHERE status = 'active'
INTO OUTFILE '/tmp/active_users.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
注:
INTO OUTFILEのパスは、MySQL サーバー上のパスであり、クライアント側のパスではありません。MySQL プロセスはこのパスに対する書き込み権限を持っている必要があり、secure_file_priv変数ではこのディレクトリへのアクセスが許可されている必要があります。
(2) LOAD DATA INFILE
サーバー側のCSVファイルからテーブルにデータをインポートする:
LOAD DATA INFILE '/tmp/active_users.csv'
INTO TABLE users_copy
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
▶ 例:CSVファイルのエクスポートとインポートの全手順
-- Export order data as CSV
SELECT order_id, customer_id, total_amount, order_date
FROM orders
WHERE order_date >= '2026-01-01'
INTO OUTFILE '/tmp/orders_2026.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';
-- Import into another table
LOAD DATA INFILE '/tmp/orders_2026.csv'
INTO TABLE orders_archive
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n';
▶ 例:LOCAL を使用したクライアントファイルのインポート
LOAD DATA LOCAL INFILE '/home/alice/data/products.csv'
INTO TABLE products
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;
6. バイナリログとポイント・イン・タイム・リカバリ
(1) バイナリログの基礎
バイナリログには、データを変更するすべてのSQL文が記録され、主にマスター・スレーブレプリケーションやポイント・イン・タイム・リカバリ(PITR)に使用されます。
-- View binlog Enabled or Disabled
SHOW VARIABLES LIKE 'log_bin%';
-- View Current binlog List of Files
SHOW BINARY LOGS;
-- View the data currently being written binlog
SHOW MASTER STATUS;
-- View binlog Details of the Incident
SHOW BINLOG EVENTS IN 'binlog.000003';
3つのバイナリログ形式:
| 形式 | 記録内容 | 長所と短所 |
|---|---|---|
| STATEMENT | SQL文を記録します | ログサイズは小さいですが、SQL文に不整合が生じる可能性があります |
| 行 | 行レベルの変更 | ログは多いが、データの整合性は良好 |
| MIXED | 混合モード | デフォルトではSTATEMENTを使用し、不明確な場合はROWに切り替える |
(2) 特定時点への復旧プロセス
特定時点への復旧における基本的なアプローチ:まず最新のフルバックアップを復元し、その後、バイナリログを再生して対象の時点まで進める。
# Steps1:Restore a Full Backup
mysql -u root -p mydb < full_backup_20260703.sql
# Steps2:Find the point in time before the error occurred
mysqlbinlog --base64-output=DECODE-ROWS -v binlog.000003 | grep -A5 "DROP TABLE"
# Steps3:Replay binlog By the target date
mysqlbinlog --start-datetime="2026-07-03 02:00:00" \
--stop-datetime="2026-07-03 14:30:00" \
binlog.000003 binlog.000004 | mysql -u root -p
▶ 例:誤ってテーブルを削除してしまった場合の特定時点への復旧
Scene: At 14:25, accidentally executed DROP TABLE orders, need to revert to 14:24:59 state
Timeline:
02:00 Full backup completed
...
14:24 Last normal operation
14:25 DROP TABLE orders (operational error)
14:30 Problem identified, start recovery
Recovery steps:
1. Restore 02:00 full backup
2. Use mysqlbinlog to replay binlog from 02:00 to 14:24:59
3. Verify orders table data integrity
# Execute the command
mysql -u root -p mydb < /backup/full_20260703.sql
mysqlbinlog --start-datetime="2026-07-03 02:00:00" \
--stop-datetime="2026-07-03 14:24:59" \
/var/lib/mysql/binlog.000003 \
/var/lib/mysql/binlog.000004 \
| mysql -u root -p mydb
7. XtraBackup による物理バックアップ
(1) XtraBackupの仕組み
XtraBackup は、Percona が開発したオープンソースの物理バックアップツールです。その基本理念は次のとおりです:
- バックグラウンドスレッド リドゥログの変更を監視しながら、InnoDBのデータページを継続的に読み込む
- バックアップ中に生成された新しいリドゥログも、継続的に記録されます。
- バックアップが完了したら、リドゥログを使用してデータページを一貫性のある状態までロールフォワードします。
- 処理全体を通じてテーブルのロックは発生しません。業務上の読み取りおよび書き込み操作には影響しません。
(2) 基本的な操作
# Full Backup
xtrabackup --backup --target-dir=/backup/full -u root -p
# Preparing to Back Up(Applications redo log,Ensure data consistency)
xtrabackup --prepare --target-dir=/backup/full
# Restore Backup
xtrabackup --copy-back --target-dir=/backup/full
# Incremental Backup(Based on the full dataset)
xtrabackup --backup --target-dir=/backup/inc1 \
--incremental-basedir=/backup/full -u root -p
# Preparing an Incremental Backup
xtrabackup --prepare --apply-log-only --target-dir=/backup/full
xtrabackup --prepare --target-dir=/backup/full \
--incremental-dir=/backup/inc1
▶ 例:XtraBackup による完全バックアップと復元
# Full Backup
xtrabackup --backup \
--target-dir=/data/backup/full_20260703 \
--user=root --password=Secret123
# Preparation Phase
xtrabackup --prepare \
--target-dir=/data/backup/full_20260703
# Stop before restoring MySQL
systemctl stop mysqld
# Clear the Data Directory and Restore
rm -rf /var/lib/mysql/*
xtrabackup --copy-back \
--target-dir=/data/backup/full_20260703
# Repair permissions and start
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld
8. バックアップ戦略の策定
(1) 完全結合と増分結合
- 毎日のフルバックアップ + リアルタイムの増分バイナリログバックアップ:中小規模のデータベースに適しており、復元も簡単です
- 週次フルバックアップ + 日次増分バックアップ(XtraBackup):大規模なデータベースに適しており、ストレージ容量を節約できます
(2) オフサイトバックアップ
データセンターレベルの災害を防ぐためには、バックアップファイルをオフサイトの保管場所に転送する必要があります:
# Usage rsync Transmit to a remote location
rsync -avz /backup/mysql/ backup-server:/data/mysql_backup/
# Usage scp Transmission
scp /backup/mysql/full_20260703.sql.gz backup-server:/data/backup/
(3) 定期的な災害復旧訓練
検証されていないバックアップは、バックアップとは言えません。少なくとも月に1回は完全な復旧訓練を実施し、以下の点を確認してください:
- バックアップファイルは通常通り解凍・復元できます
- 復旧後にデータ整合性チェックに合格した
- 復旧時間は許容可能なRTOの範囲内である
| データ量 | フルバックアップの頻度 | 増分バックアップの方法 | オフサイト戦略 | 復旧訓練 |
|---|---|---|---|---|
| 10 GB以下 | 毎日のフルバックアップ | バイナリログ | 毎日の転送 | 月に1回 |
| 10~100 GB | 毎日のフルバックアップ | バイナリログ | 毎日の転送 | 月に1回 |
| 100 GB – 1 TB | 毎週のフルバックアップ | 毎日のXtraBackup増分バックアップ | 毎週のデータ転送 | 四半期ごと |
| > 1 TB | 毎週のフルバックアップ | 毎日のXtraBackup増分バックアップ | リアルタイム同期 | 四半期ごと |
| 復旧方法 | 適用可能なシナリオ | 復旧速度 | 難易度 | データの粒度 |
|---|---|---|---|---|
| mysqldumpによる完全復元 | 誤ってデータベースを削除した場合/データベースの完全移行 | 処理が遅い | 負荷が低い | データベース全体 |
| バイナリログによる特定時点への復旧 | ユーザーエラーによるロールバック | 中 | 高 | 1秒未満 |
| XtraBackup の復元 | ハードウェア障害・災害 | 高速 | 中速 | データベース全体 |
| LOAD DATA INFILE | 単一テーブルのデータ更新 | 高速 | 低 | 単一テーブル |
9. 自動バックアップと詳細な例
(1) 自動バックアップの要点
- crontab を使用して、バックアップスクリプトをスケジュール通りに実行する
- バックアップファイルは日付で名前が付けられているため、見つけやすい
- 自動圧縮により容量を節約できます
- 有効期限が切れたバックアップを定期的に削除する(N日間は保持する)
- バックアップが完了したら通知を送信する
▶ 例:自動バックアップスクリプト
#!/bin/bash
# mysql_backup.sh - MySQL Automated Backup Script
BACKUP_DIR="/data/backup/mysql"
RETAIN_DAYS=7
DB_USER="root"
DB_PASS="Secret123"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/mysql_backup.log"
mkdir -p $BACKUP_DIR
echo "[$DATE] Start Backup..." >> $LOG_FILE
mysqldump -u$DB_USER -p$DB_PASS \
--all-databases --single-transaction \
--routines --triggers --set-gtid-purged=OFF \
| gzip > $BACKUP_DIR/full_${DATE}.sql.gz
if [ $? -eq 0 ]; then
SIZE=$(du -sh $BACKUP_DIR/full_${DATE}.sql.gz | cut -f1)
echo "[$DATE] Backup Successful,Size: $SIZE" >> $LOG_FILE
else
echo "[$DATE] Backup Failed!" >> $LOG_FILE
exit 1
fi
find $BACKUP_DIR -name "full_*.sql.gz" -mtime +$RETAIN_DAYS -delete
echo "[$DATE] Cleanup ${RETAIN_DAYS} Backup from X days ago" >> $LOG_FILE
▶ 例:バックアップおよび復元スクリプトの完全版
#!/bin/bash
# full_backup_restore.sh - Complete Backup and Recovery Verification Script
BACKUP_DIR="/data/backup/mysql"
MYSQL_USER="root"
MYSQL_PASS="Secret123"
REMOTE_HOST="backup-server"
REMOTE_DIR="/data/mysql_backup"
DATE=$(date +%Y%m%d)
LOG="/var/log/backup_restore.log"
echo "=== $DATE Backup and Recovery Process ===" >> $LOG
# 1. Full Backup
mysqldump -u$MYSQL_USER -p$MYSQL_PASS \
--all-databases --single-transaction \
--routines --triggers \
| gzip > $BACKUP_DIR/full_${DATE}.sql.gz
echo "[$DATE] Full backup completed" >> $LOG
# 2. Refresh and Record binlog Location
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "FLUSH BINARY LOGS;"
BINLOG_FILE=$(mysql -u$MYSQL_USER -p$MYSQL_PASS \
-N -e "SHOW MASTER STATUS;" | awk '{print $1}')
echo "[$DATE] Currently binlog: $BINLOG_FILE" >> $LOG
# 3. Backup binlog Documents
cp /var/lib/mysql/$BINLOG_FILE $BACKUP_DIR/
echo "[$DATE] binlog Backed up" >> $LOG
# 4. Long-distance transmission
rsync -avz $BACKUP_DIR/full_${DATE}.sql.gz \
$REMOTE_HOST:$REMOTE_DIR/ >> $LOG 2>&1
echo "[$DATE] Remote transmission complete" >> $LOG
# 5. Restore Verification(In the temporary database)
mysql -u$MYSQL_USER -p$MYSQL_PASS \
-e "CREATE DATABASE IF NOT EXISTS verify_db;"
gunzip < $BACKUP_DIR/full_${DATE}.sql.gz | \
mysql -u$MYSQL_USER -p$MYSQL_PASS verify_db
ROW_COUNT=$(mysql -u$MYSQL_USER -p$MYSQL_PASS \
-N -e "SELECT COUNT(*) FROM verify_db.users;")
echo "[$DATE] Verification users Number of lines: $ROW_COUNT" >> $LOG
# 6. Clean Up the Validation Database and Expired Backups
mysql -u$MYSQL_USER -p$MYSQL_PASS -e "DROP DATABASE verify_db;"
find $BACKUP_DIR -name "full_*.sql.gz" -mtime +7 -delete
echo "=== $DATE The backup and restore process is complete ===" >> $LOG
毎日午前2時に実行されるcrontabジョブを設定します:
0 2 * * * /usr/local/bin/full_backup_restore.sh
❓ よくある質問
--single-transaction パラメータを使用する場合、InnoDB テーブルはロックされません。MVCC 一貫性スナップショットを使用して読み込まれます。MyISAM テーブルは読み取りロックを取得します。利用の少ない時間帯にバックアップを行うか、XtraBackup に切り替えることをお勧めします。mysqlcheck --check を使用して復元されたテーブルを確認することもできます。この確認は、少なくとも月に1回行ってください。mysqlbinlog を使用して DROP TABLE ステートメントの直前の時点までバイナリログを再生します。最後に、一時データベースから削除されたテーブルのデータをエクスポートし、本番データベースに再挿入します。secure_file_priv OUTFILE のパスに制限がある場合はどうすればよいですか?secure_file_priv を特定のディレクトリ(例:/var/lib/mysql-files/)に設定するか、mysql -e "SELECT ..." を使用してクライアント側のファイルにリダイレクトし、サーバー側の制限を回避してください。--throttleパラメータが用意されています。バックアップは利用のピーク時間を避けて実行するか、レート制限パラメータを設定することをお勧めします。📖 まとめ
- mysqldump は、最も一般的に使用されている論理バックアップツールであり、フル、単一データベース、単一テーブル、構造、データの5つのモードをサポートしています。
- --single-transaction パラメータは、InnoDB のバックアップ時にテーブルがロックされないようにするものであり、本番環境では不可欠です。
- 論理バックアップを復元する2つの方法:mysql < file.sql および SOURCE
- SELECT INTO OUTFILE / LOAD DATA INFILE は、CSV形式のデータのインポートおよびエクスポートに適しています
- binlog により、ポイント・イン・タイム・リカバリ(PITR)が可能となり、誤って実行した操作を1秒未満の精度でロールバックすることができます。
- XtraBackup は、テーブルをロックすることなく高速な物理バックアップを実行できるため、大規模なデータベースに適しています
- バックアップ戦略は、データ量に応じて選択する必要があります。小規模なデータベースでは毎日フルバックアップを行い、大規模なデータベースでは毎週フルバックアップに加え、毎日増分バックアップを行うようにします。
- オフサイトバックアップと定期的な復旧訓練は、バックアップの効果を確実にするための鍵となります
📝 練習問題
-
基本問題(難易度:⭐):
mysqldumpを使用してデータベースをバックアップし、それを新しいデータベースに復元してください。元のデータベースと復元されたデータベースのテーブル数および行数を比較してください。 -
基本演習(難易度:⭐):
SELECT INTO OUTFILEを使用してテーブルから CSV ファイルにデータをエクスポートし、LOAD DATA INFILEを使用して別のテーブルにインポートし、データが一致していることを確認してください。 -
上級演習(難易度:⭐⭐):テーブルが誤って削除されてしまったというシナリオをシミュレートします。まず、フルバックアップを実行し、次にいくつかのINSERT操作を実行します。その後、DROP TABLEコマンドを実行し、最後にバイナリログを用いたポイント・イン・タイム復元を使用して、DROP実行前の状態に戻します。
-
上級演習(難易度:⭐⭐):毎日フルバックアップを自動的に実行し、gzipで圧縮し、バックアップを7日間保持し、バックアップ結果に関する通知メールを送信するシェルスクリプトを作成してください。
-
課題問題(難易度:⭐⭐⭐):フルバックアップ、増分バックアップ、オフサイトバックアップ、およびテストの4つの側面を網羅した包括的なバックアップ戦略を策定してください。200 GBの本番用データベースについて、使用するツール、実行頻度、復旧手順、および検証方法を具体的に明記してください。



