運用中に誤ってdropやtruncateなどしてしまい、
今回は特定テーブルをロールバックする流れを、
- バイナリログを直接適用してリカバリする方法
- レプリケーション機能を使用してリカバリする方法
フルバックアップについて
今回はフルバックアップの方法について深くは説明しないので、
バックアップ取得には、
- 論理バックアップ
- mysqldump
(オンラインバックアップ) - mysqlpump
(オンラインバックアップ) - mydumper
(オンラインバックアップ)
- mysqldump
- 物理バックアップ
-
- MySQL Enterprise Backup
(オンラインバックアップ) - xtrabackup
(オンラインバックアップ) - MySQLを停止して、
cpコマンドなどで物理コピー (オフラインバックアップ) - MySQL Enterprise Backup
特定のテーブルをロールバックする
ここからは例を交えて説明したいと思います。
運用中にUSER_
テーブルを誤ってtruncateしてしまい、
該当のtruncate文を探す
まずは、mysql-bin
としています)。
[root]# mysqlbinlog mysql-bin.000010 | grep -i -B6 truncate # at 29935 #170515 10:36:32 server id 1 end_log_pos 3025 CRC32 0x9518b1e8 Anonymous_GTID last_committed=11 sequence_number=12 SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/; # at 30000 #170515 10:36:32 server id 1 end_log_pos 3106 CRC32 0x1ebd34e9 Query thread_id=7 exec_time=0 error_code=0 SET TIMESTAMP=1494812192/*!*/; truncate table USER_LOG
表示された内容にat 30000
とあるので、at 29935
からそのtruncate文の直前の処理のポジションもわかります。今回は2つのリカバリ方法を紹介するため、
フルバックアップを使用してリストアする
今回はこの手順の詳しい内容は割愛しますが、
該当のtruncate文直前までリカバリを行う
今回は2つの方法を紹介します。
バイナリログを直接適用してリカバリする
こちらはマニュアルに記載された一般的方法です。詳しくは7.
mysqlbinlogコマンドを使用して、
該当のバイナリログをコピーしてきて、
# mysqlbinlog --start-position=1000 mysql-bin.000008 | mysql -uroot -p # mysqlbinlog mysql-bin.000009 | mysql -uroot -p # mysqlbinlog --stop-position=30000 mysql-bin.000010 | mysql -uroot -p
- バイナリログ:mysql-bin.
000008、 ポジション:1000を開始ポジションとする - バイナリログ:mysql-bin.
000010、 truncate文を実行するポジション:30000を終了ポジションとする
ここで注意点がいくつかあります。
--start-position
は指定したポジションから開始され、そのポジションの処理を含めて出力される --stop-position
は指定したポジションで終了され、そのポジションの処理は含まれない
よって、--stop-position
に30000
を指定することで、
また、CREATE TEMPORARY TABLE
文がバイナリログを跨ぐ場合は、
# mysqlbinlog --start-position=1000 --stop-position=30000 mysql-bin.000008 mysql-bin.000009 mysql-bin.000010 | mysql -uroot -p
このように記述すると、--start-position
は最初に指定した引数のバイナリログに有効で、--stop-position
は最後に指定した引数のバイナリログに有効となります。記述ミスなどでバイナリログの順番を誤ってしまうと、CREATE TEMPORARY TABLE
文が存在しない場合は複数回に分けて実施する方が安全かもしれません。
mysqlbinlogコマンドを使用する方法は簡単に実行できますが、
- どのバイナリログのどのポジションまで適用されているかなどの途中経過を把握できない。
- フルリカバリとなり特定のテーブルのみをリカバリできない。
レプリケーション機能を使用してリカバリする
これはtruncateしてしまったMySQLをマスターにして、START SLAVE UNTIL
文を使用してバイナリログとポジションを指定します。その指定した箇所に到達することで、
まずは、CHANGE MASTER
文にmysqldumpで取得したバックアップのポジションを指定してレプリケーション開始前まで準備します。レプリケーションするための権限は、
mysql> CHANGE MASTER TO master_host='hostname', master_port=3306, master_user='user', master_password='xxxx', master_log_file='mysql-bin.000008', master_log_pos=1000;
このあとに、START SLAVE UNTIL
文を実行します。mysqlbinlogコマンドでは--stop-position
に30000を指定しましたが、29935
を指定する必要があります。なぜなら、START SLAVE UNTIL
文の場合は指定したポジションを含めて実行してからSQL_
mysql> START SLAVE UNTIL MASTER_LOG_FILE='mysql-bin.000010', MASTER_LOG_POS=29935;
そうすると、
mysql> SHOW SLAVE STATUS¥G (一部割愛) Master_Log_File: binary_log.000015 Read_Master_Log_Pos: 150989977 Relay_Master_Log_File: binary_log.000010 Slave_IO_Running: YES Slave_SQL_Running: No ・ Exec_Master_Log_Pos: 29935 ・ Until_Log_File: mysql-bin.000010 Until_Log_Pos: 29935
IO_Master_
とRead_
は進んでいますが、Relay_
とExec_
からUSER_
テーブルをtruncateする直前の状態のデータになっていることがわかります。
この方法は開始するまでが少し手間ですが、
- どのバイナリログのどのポジションまで適用されているか、
などの途中経過を SHOW SLAVE STATUS
から確認可能 - MySQL起動時に
Replicate_
オプションに対してDo_ Table USER_
テーブルを指定することで、LOG 特定のテーブルのみリカバリすることも可能
START SLAVE UNTIL
文はGTID有効化でも使用できます。詳しくはマニュアル13.
注意点として、skip-slave-start
オプションを指定しておくとより安全です。
対象のテーブルを確認する
ここまで終わると、USER_
テーブルをmysqldumpでエクスポート、
最後に
今回は特定テーブルをロールバックさせる方法について説明しました。通常の運用ではこのようなことは絶対にしたくない作業ですが、