alibaba cloud RDSのbinlogについて検証してみた

# 前提
- alibaba cloud上でRDS MySQL8のインスタンスがすでに作られている。
- RDSに以下の三種類がありまして、今回の検証は基礎版`Basic`で問題ありません。
    - `Basic` : 一つのinstanceしかありません。一時的な検証やテスト環境、開発環境など本番環境以外で利用されるのは一般的です。
    - `High-availability`: 
        - AWS RDSのmulti AZに似ている機能です
        - primary instanceとsecondary instance(standby instance)の２つのinstanceで構成されている
        - userから見ると、通常はprimary instanceしか利用されていない。
        - secondary instanceはあくまでもstandby用であり、primary instanceが利用できない時は自動的にsecondary instanceにfail overすることになる。
    - `Enterprise`：
        - 一つのprimary instance, 一つのsecondary instance, 一つのlogger instanceという合計３つのinstanceから構成されている
        - 非常に高い可用性が求められている金融系などによく利用されている

https://www.alibabacloud.com/help/en/apsaradb-for-rds/latest/quick-start-create-an-apsaradb-rds-for-mysql-instance


# binlogについて
- binlogはstorage engineとは関係なくて、上位のexcution engine(layer)の機能であり、つまりinnodbとMyISAMのどちらのストレージエンジンを使っても、binlogが生成されるということです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/b1479c83-1736-d763-19e3-7b210cf35651.png)
- binlogはバイナリ形式でディスクに保存される論理ログ
- binlogは、データベースに対するすべてのDDLおよびDML操作（SELECTやSHOWなど、データそのものを変更しないコマンドを除く）を記録します。
- 誤って削除したデータを復元する場合、binlogを利用します。データベースのバックアップをベースに、バックアップ時点から指定時点の間のbinlogを適用することで、指定時点のデータを復元できます。
- また、マスタスレーブ構成で２つ以上のデータベースサーバが存在する場合、マスタサーバからスレーブサーバにbinlogの内容を転送します。スレーブサーバがbinlogを適用して、マスタサーバのデータと一致性を保ちます。


binglogとredo logの違いについては以下をご参考ください。

https://www.ipride.co.jp/blog/3660#:~:text=binlog%E3%81%AF%E3%80%81Server%E5%B1%A4%E3%81%8C,%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%97%E3%81%BE%E3%81%99%E3%80%82


# 検証内容
- RDSのbinlogはデフォルトで有効であり、しかも無効にすることができない。

https://www.alibabacloud.com/help/en/apsaradb-for-rds/latest/rds-mysql-database-limits

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/0a0eb6b9-c9c3-5745-4057-4416d0cc2291.png)

```
mysql> SHOW VARIABLES LIKE 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+

mysql> SET GLOBAL log_bin=0;
ERROR 1238 (HY000): Variable 'log_bin' is a read only variable
```

- binlogのフォーマットに以下の三種類がありますが、RDSはRBRであり、しかも変更することもできない。
  - SBR(statement base replication)：
    - insert,update,deleteなどのクエリ文がそのままバイナリログに記録される方式
    - sysdate()などの実行時点で結果が変わってしまうような関数が起因し、復元前と完全に一致しない場合があるため、こちらを選択する理由はそもそもないだろう
    - 以前はSTATEMENTがデフォルトでしたが、MySQL8.0からデフォルトはROWになっています。
  - RBR(row base replication)：
    - 更新された行のデータそのものがバイナリログに記録される方式
    - SQL 文 (UPDATE,INSERT,DELETE) が base64 エンコードされる
  - MBR(mixed base replication)：処理の内容に応じて同期にモードを切り替えられる
    - 実行時点で結果が変わってしまうような関数の場合は、自動的に更新された行のデータそのものがバイナリログに記録される
    - そうでないクエリはクエリ文そのままバイナリログに記録される方式

https://blog.kazu69.net/2015/12/01/examined-mysql-binlog-format/

https://qiita.com/ponkotuy/items/b23233151485c6a4fb18

https://qiita.com/kaburankattara/items/2a8e43b82c8b00832847


```
mysql> SHOW GLOBAL VARIABLES LIKE 'binlog_format';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+

mysql> SET GLOBAL binlog_format = 'MIXED';
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation
```

- DDLおよびDML操作をしなくても、数秒ごとにbinlogにログが追加される
```
mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000004 |    443190 | No        |
| mysql-bin.000005 |    137446 | No        |
+------------------+-----------+-----------+

mysql> show binary logs;
+------------------+-----------+-----------+
| Log_name         | File_size | Encrypted |
+------------------+-----------+-----------+
| mysql-bin.000004 |    443190 | No        |
| mysql-bin.000005 |    137751 | No        |
+------------------+-----------+-----------+
```
→数秒経ったら、上記の`mysql-bin.000005`の`File_size`は変わってしまう。

  - mysqlbinlogコマンドbinlogを取得してみる
 ```
$ mysqlbinlog -h rm-****.mysql.japan.rds.aliyuncs.com -u wangdan --read-from-remote-server --result-file=binlog mysql-bin.000005 -p

$ tail -n 20 binlog
BEGIN
/*!*/;
# at 148271
#220825 19:57:04 server id 100100013  end_log_pos 148339 CRC32 0xd008eee2 	Table_map: `mysql`.`ha_health_check` mapped to number 122
# at 148339
#220825 19:57:04 server id 100100013  end_log_pos 148395 CRC32 0xd91f45ea 	Update_rows_v1: table id 122 flags: STMT_END_F

BINLOG '
gFUHYxOtZ/cFRAAAAHNDAgAAAHoAAAAAAAEABW15c3FsAA9oYV9oZWFsdGhfY2hlY2sAAgj+Av4D
AQEBAAIBIeLuCNA=
gFUHYxitZ/cFOAAAAKtDAgAAAHoAAAAAAAEAAv//ALvBpdSCAQAAAW0AjPyl1IIBAAABbepFH9k=
'/*!*/;
# at 148395
#220825 19:57:04 server id 100100013  end_log_pos 148426 CRC32 0xc459ca5f 	Xid = 155492
COMMIT/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

 ```
binlogから`mysql`.`ha_health_check`がupdateされていたようなので、中身を確認してみると数秒ごとにidが変わっていたことが分かりました。
おそらく、可用性担保するためには内部で数秒ごとにhealth checkがされていて、health checkの結果がシステムdatabaseの`mysql`の`ha_health_check`というテーブルに書き込まれているようです。
```
mysql> select * from mysql.ha_health_check;
+---------------+------+
| id            | type |
+---------------+------+
| 1661425174265 | k    |
| 1661425174254 | m    |
+---------------+------+

mysql> select * from mysql.ha_health_check;
+---------------+------+
| id            | type |
+---------------+------+
| 1661425189252 | k    |
| 1661425189223 | m    |
+---------------+------+
```
- binlogにはSQL文(UPDATE,INSERT,DELETE) が base64 エンコードされていること

## binlogのバックアップについて
- デフォルトでbinlogはリアルタイムにRDS instaceのローカルから専用のバックアップ空間にbackupされる(無効にすることもできる)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/c2b68a92-4ac6-da04-20d9-e0412ba90054.png)
- RDS instaceのローカルに保持していbinlogは以下の設定によって一定時間ごとに自動的に削除される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/28664/e5ca73a9-d3ef-e16d-270b-6beda2064175.png)