DBのテーブルを消した想定で、ロールフォワードする

# はじめに

間違えてデータを消してしまった場合のテーブルの`リストア → リカバリ`を行い、ロールフォワードをしてみたいと思います

# 環境

```
[環境]
docker
mysql8
```

# 大まかな手順

1. dbとテーブル作成して、1件データをinsertする
1. バックアップをとる
1. 再度、1件データを投入
1. テーブルを削除する
1. リストアと、リカバリを行ってデータの復元をする

# テーブル復旧まで実際に行う

## 1. dbとテーブル作成して、1件データをinsertする

```
docker-compose exec db bash
mysql -u [DB_USER] -p

mysql> use practice;
mysql> CREATE TABLE ice_cream (id int, name varchar(36));
mysql> INSERT INTO ice_cream (id, name) VALUES ("1", "haagen dazs");
mysql> SELECT * FROM ice_cream;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | haagen dazs |
+------+-------------+
```

## 2. バックアップをとる

バイナリログはデフォルトでは作成されないです。
バイナリログを出力するために、`/etc/my.cnf`以下の設定をします

```/etc/my.cnf
[mysqld]
# binary logging is required for replication
log-bin=mysql-bin
# binary logging format - mixed recommended
binlog_format=mixed
```

そして、バックアップを取ります

```
mysqldump -u root -p practice > backup.dump
```

ログをフラッシュする

```
mysql -u root -p practice -e "flush logs;"
```

フラッシュする理由としては、**リストア（復旧）がスムーズに行えます。**

![スクリーンショット 2023-02-18 10.10.54.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536974/d540b04e-f917-fc14-dbfe-0367e45b9e67.jpeg)

* フラッシュする事で、バイナリログがローテートされて新しいログファイルが作成されます
* 新しいバイナリログからロールフォワードを行うことで、**バックアップ直後 ~ 障害直前**までの分も戻すことが可能です
* フラッシュを行わないと、復元箇所を探す必要があるので作業手順が増えます

```
ls -la var/lib/mysql/binlog.*
-rw-r----- 1 mysql mysql 942 Feb 18 10:47 var/lib/mysql/binlog.000001
-rw-r----- 1 mysql mysql 157 Feb 18 10:47 var/lib/mysql/binlog.000002
-rw-r----- 1 mysql mysql  32 Feb 18 10:47 var/lib/mysql/binlog.index
```

`binlog.000002`が増えました

本来は、バイナリログは同一サーバ内に置いておくべきではないようです。
AWS S3など外部のファイルサーバーに置きます

## 3. 再度、1件データを投入

バックアップを取った後にDBを更新されたことを再現するため 1件データを追加します

```
mysql> INSERT INTO ice_cream (id, name) VALUES ("2", "sou");

mysql> SELECT * FROM ice_cream;
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | haagen dazs |
|    2 | sou         |
+------+-------------+
```

```
ls -la var/lib/mysql/binlog.*
-rw-r----- 1 mysql mysql 942 Feb 18 10:47 var/lib/mysql/binlog.000001
-rw-r----- 1 mysql mysql 453 Feb 18 10:51 var/lib/mysql/binlog.000002
-rw-r----- 1 mysql mysql  32 Feb 18 10:47 var/lib/mysql/binlog.index
```

`Feb 18 10:51`：バイナリログの日時が更新されました

バイナリログを`binlog/`へコピーして退避します

```
mkdir /var/lib/mysql/binlog/
cp -f /var/lib/mysql/binlog.* /var/lib/mysql/binlog/
```

## 4. テーブルを削除する

誤ってテーブルを削除してしまった場合を再現します

```
mysql> drop table ice_cream;
mysql> show tables;
Empty set (0.02 sec)
```


## 5. リストアと、リカバリを行ってデータの復元をする

まずは、バックアップデータからリストアを行います

```
mysql -u root -p practice < backup.dump

mysql -u root -p practice -e "show tables; select * from ice_cream;"
+-------------------+
| Tables_in_failure |
+-------------------+
| ice_cream         |
+-------------------+
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | haagen dazs |
+------+-------------+
```

バックアップ時点のデータまで復旧することが出来ました
続いて、ロールフォワードリカバリを行います

テーブルが消える前には、`|    2 | sou         |` もデータとして存在していたので戻します

バイナリ形式 → テキスト形式 へと変換し、`/tmp/recover.sql`へと出力します。
その後、`practice`へのリカバリを行います

```
mysqlbinlog --no-defaults -D -u root -p var/lib/mysql/binlog/binlog.000002 > /tmp/recover.sql
mysql -u root -p practice < /tmp/recover.sql
mysql -u root -p practice -e "select * from ice_cream;"
+------+-------------+
| id   | name        |
+------+-------------+
|    1 | haagen dazs |
|    2 | sou         |
+------+-------------+
```

これで、復旧完了しました

（本来は、障害対策としてマスター/スレーブ構成にしてレプリケーションを行うようです）

# 参考

https://www.amazon.co.jp/%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6DB%E8%A8%AD%E8%A8%88-%E5%BE%B9%E5%BA%95%E6%8C%87%E5%8D%97%E6%9B%B8-%E5%88%9D%E7%B4%9A%E8%80%85%E3%81%A7%E7%B5%82%E3%82%8F%E3%82%8A%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84%E3%81%82%E3%81%AA%E3%81%9F%E3%81%B8-%E3%83%9F%E3%83%83%E3%82%AF/dp/4798124702

https://hit.hateblo.jp/entry/2016/03/04/210936