404 Not Found

404 Not Found


nginx

『MySQLのバックアップと復旧完全ガイド』

アリスの会社のサーバーのハードドライブが突然故障し、データベースが完全にダウンしてしまいました。バックアップがなかったため、3年分の顧客データ、注文記録、財務情報が永久に失われてしまった。この大惨事は彼女にとって警鐘となり、包括的なバックアップシステムの構築へとつながった。具体的には、毎日のmysqldumpによるフルバックアップ、継続的な増分binlogバックアップ、週1回のオフサイトへのデータ転送、そして月1回の復旧訓練である。それ以来、たとえ再びハードウェア障害が発生したとしても、彼女は30分以内にすべてのデータを完全に復元できるようになった。

このレッスンでは、次のことを学びます:

100%
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 TABLEINSERT といったステートメントを含む SQL テキストファイルとして保存します。データを復元するには、これらの SQL ステートメントを再実行するだけで済みます。代表的なツールとして mysqldump が挙げられます。

利点: 高い可読性、バージョン間の互換性、および個々のデータベースやテーブルを選択的にバックアップできる機能。

デメリット: 処理速度が遅い;バックアップと復元の両方にMySQLプロセスの関与が必要;大規模なデータベースでは時間がかかる。

(2) 物理バックアップの概要

物理バックアップでは、データベースの基盤となるデータファイル(.ibd.frm など)が直接コピーされます。復元するには、これらのファイルをデータディレクトリにコピーし直すだけで済みます。代表的なツールとして XtraBackup が挙げられます。

利点: 高速、テーブルロックなし(InnoDB)、大規模なデータベースに適している。

デメリット: 人間が読み取れないこと、クロスプラットフォームの互換性が限られていること、そして一貫性を維持するためにダウンタイムが必要になるか、専用のツールを使用する必要があること。

比較項目 論理バックアップ (mysqldump) 物理バックアップ (XtraBackup)
バックアップ対象 SQL文 データファイルのコピー
バックアップ速度 遅い(行単位のエクスポート) 速い(ファイルコピー)
復旧速度 遅い(SQLを1行ずつ実行する) 速い(ファイルをコピーして復元する)
テーブルロックの影響 InnoDBのロックフリー テーブルロックなし
可読性 高 (プレーンテキストのSQL) 低 (バイナリファイル)
ストレージのオーバーヘッド 低(テキストの圧縮率が高い) 高(ファイルの完全コピー)
バージョン間 互換性あり バージョンの一致が必要
ユースケース 50 GB以下の中小規模データベース 50 GBを超える大規模データベース

3. mysqldump による論理バックアップの詳細な解説

(1) 完全バックアップ

フルバックアップでは、すべてのデータベースからすべてのデータがエクスポートされます。これは、最も基本的かつ安全なバックアップ方法です。

BASH
mysqldump -u root -p --all-databases --single-transaction > full_backup.sql

--single-transaction パラメータは、InnoDB テーブルの読み取り処理において一貫性スナップショットを使用し、テーブルをロックしません。MyISAM テーブルは引き続きロックされます。

(2) 単一データベースおよび単一テーブルのバックアップ

BASH
# 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) 構造とデータの分離

BASH
# 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 つのバックアップモード

BASH
# 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ファイルから、指定したデータベースにデータを復元する:

BASH
mysql -u root -p mydb < mydb_backup.sql

圧縮されたバックアップファイルを復元する:

BASH
gunzip < mydb_backup.sql.gz | mysql -u root -p mydb

(2) SOURCE コマンドによる復元

MySQL クライアント内の SOURCE コマンドを使用して復元します:

SQL
USE mydb;
SOURCE /var/backups/mysql/mydb_backup.sql;

▶ 例:復旧プロセス

BASH
# 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;"

▶ 例:圧縮バックアップの復元

BASH
# 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ファイルにエクスポートします:

SQL
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ファイルからテーブルにデータをインポートする:

SQL
LOAD DATA INFILE '/tmp/active_users.csv'
INTO TABLE users_copy
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 ROWS;

▶ 例:CSVファイルのエクスポートとインポートの全手順

SQL
-- 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 を使用したクライアントファイルのインポート

SQL
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)に使用されます。

SQL
-- 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) 特定時点への復旧プロセス

特定時点への復旧における基本的なアプローチ:まず最新のフルバックアップを復元し、その後、バイナリログを再生して対象の時点まで進める

BASH
# 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

▶ 例:誤ってテーブルを削除してしまった場合の特定時点への復旧

TEXT
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
BASH
# 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 が開発したオープンソースの物理バックアップツールです。その基本理念は次のとおりです:

  1. バックグラウンドスレッド リドゥログの変更を監視しながら、InnoDBのデータページを継続的に読み込む
  2. バックアップ中に生成された新しいリドゥログも、継続的に記録されます。
  3. バックアップが完了したら、リドゥログを使用してデータページを一貫性のある状態までロールフォワードします。
  4. 処理全体を通じてテーブルのロックは発生しません。業務上の読み取りおよび書き込み操作には影響しません。

(2) 基本的な操作

BASH
# 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 による完全バックアップと復元

BASH
# 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) 完全結合と増分結合

(2) オフサイトバックアップ

データセンターレベルの災害を防ぐためには、バックアップファイルをオフサイトの保管場所に転送する必要があります:

BASH
# 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回は完全な復旧訓練を実施し、以下の点を確認してください:

データ量 フルバックアップの頻度 増分バックアップの方法 オフサイト戦略 復旧訓練
10 GB以下 毎日のフルバックアップ バイナリログ 毎日の転送 月に1回
10~100 GB 毎日のフルバックアップ バイナリログ 毎日の転送 月に1回
100 GB – 1 TB 毎週のフルバックアップ 毎日のXtraBackup増分バックアップ 毎週のデータ転送 四半期ごと
> 1 TB 毎週のフルバックアップ 毎日のXtraBackup増分バックアップ リアルタイム同期 四半期ごと
復旧方法 適用可能なシナリオ 復旧速度 難易度 データの粒度
mysqldumpによる完全復元 誤ってデータベースを削除した場合/データベースの完全移行 処理が遅い 負荷が低い データベース全体
バイナリログによる特定時点への復旧 ユーザーエラーによるロールバック 1秒未満
XtraBackup の復元 ハードウェア障害・災害 高速 中速 データベース全体
LOAD DATA INFILE 単一テーブルのデータ更新 高速 単一テーブル

9. 自動バックアップと詳細な例

(1) 自動バックアップの要点

▶ 例:自動バックアップスクリプト

BASH
#!/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

▶ 例:バックアップおよび復元スクリプトの完全版

BASH
#!/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ジョブを設定します:

BASH
0 2 * * * /usr/local/bin/full_backup_restore.sh

❓ よくある質問

Q mysqldump はテーブルをロックしますか?
A --single-transaction パラメータを使用する場合、InnoDB テーブルはロックされません。MVCC 一貫性スナップショットを使用して読み込まれます。MyISAM テーブルは読み取りロックを取得します。利用の少ない時間帯にバックアップを行うか、XtraBackup に切り替えることをお勧めします。
Q バイナリログとリドゥログの違いは何ですか?
A リドゥログはInnoDBエンジンレベルのログであり、クラッシュリカバリに使用され、循環方式で書き込まれます。一方、バイナリログはMySQLサーバーレベルのログであり、マスター・スレーブレプリケーションやポイント・イン・タイム・リカバリに使用され、末尾に順次書き込まれ、アーカイブに適しています。記録される内容や目的は、この2つで全く異なります。
Q バックアップファイルのサイズはどのくらいですか?
A 論理バックアップは、元のデータサイズ(テキスト形式)の約30%~80%であり、gzip圧縮後は約10%~30%になります。物理バックアップは、元のデータサイズとほぼ同じです。データ量の3倍に相当するストレージ容量を確保することをお勧めします。
Q バックアップが正常に利用できることを確認するにはどうすればよいですか?
A テスト環境で定期的に完全復元を実行し、テーブル数、行数、および重要な業務データを確認してください。また、mysqlcheck --check を使用して復元されたテーブルを確認することもできます。この確認は、少なくとも月に1回行ってください。
Q 誤って削除してしまったテーブルを復元するにはどうすればよいですか?
A 最新のフルバックアップを一時データベースに復元し、mysqlbinlog を使用して DROP TABLE ステートメントの直前の時点までバイナリログを再生します。最後に、一時データベースから削除されたテーブルのデータをエクスポートし、本番データベースに再挿入します。
Q secure_file_priv OUTFILE のパスに制限がある場合はどうすればよいですか?
A secure_file_priv を特定のディレクトリ(例:/var/lib/mysql-files/)に設定するか、mysql -e "SELECT ..." を使用してクライアント側のファイルにリダイレクトし、サーバー側の制限を回避してください。
Q XtraBackupはバックアップ中のパフォーマンスに影響を与えますか?
A 多少のI/Oオーバーヘッドは発生しますが、XtraBackupにはI/Oレートを制限するための--throttleパラメータが用意されています。バックアップは利用のピーク時間を避けて実行するか、レート制限パラメータを設定することをお勧めします。

📖 まとめ


📝 練習問題

  1. 基本問題(難易度:⭐)mysqldump を使用してデータベースをバックアップし、それを新しいデータベースに復元してください。元のデータベースと復元されたデータベースのテーブル数および行数を比較してください。

  2. 基本演習(難易度:⭐)SELECT INTO OUTFILE を使用してテーブルから CSV ファイルにデータをエクスポートし、LOAD DATA INFILE を使用して別のテーブルにインポートし、データが一致していることを確認してください。

  3. 上級演習(難易度:⭐⭐):テーブルが誤って削除されてしまったというシナリオをシミュレートします。まず、フルバックアップを実行し、次にいくつかのINSERT操作を実行します。その後、DROP TABLEコマンドを実行し、最後にバイナリログを用いたポイント・イン・タイム復元を使用して、DROP実行前の状態に戻します。

  4. 上級演習(難易度:⭐⭐):毎日フルバックアップを自動的に実行し、gzipで圧縮し、バックアップを7日間保持し、バックアップ結果に関する通知メールを送信するシェルスクリプトを作成してください。

  5. 課題問題(難易度:⭐⭐⭐):フルバックアップ、増分バックアップ、オフサイトバックアップ、およびテストの4つの側面を網羅した包括的なバックアップ戦略を策定してください。200 GBの本番用データベースについて、使用するツール、実行頻度、復旧手順、および検証方法を具体的に明記してください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%