Amazon Aurora MySQLクラスター間でbinlogレプリケーションを構築し運用検証する


# はじめにの要件

「同一のAWSリージョン内で2つのAurora MySQLクラスター間でレプリケーションを貼る」

この要件に対応するためには現時点(2024年12月時点)では、"MySQL binary log (binlog) replication"を利用する必要があります。

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.html

> Two Aurora MySQL DB clusters in the same AWS Region, by using MySQL binary log (binlog) replication.

本記事では、Amazon Aurora MySQLクラスター間でbinlogレプリケーションを構築する方法と、レプリケーション実行中の障害時の検証をします。

binlogレプリケーションはMySQLの機能です。そもそもの構成や仕組みについてはこの記事では触れないので公式ドキュメントや別記事を参照ください。

# 前提

本記事では以下の前提があります。

* Aurora MySQLのバージョンは`8.0.mysql_aurora.3.04.2`(MySQL8.0.28)
* 本記事ではレプリケーションにてレプリ元となるクラスターを"Source側"、レプリ先となる方(Replica)を"Target側"と呼ぶ
* レプリケーションTargetとなるMySQLクラスターはSourceのクラスターからcloneを元に作成する
* binlogレプリケーションではGTIDモードを採用する

# GTIDについて

Global Transaction Identifiers (GTID) はトランザクションごとに全体ユニークなIDを付与する仕組みでbinlogレプリケーションにおいては以下のメリットがあります。

* Masterサーバがフェイルオーバーした際にbinlogファイルとそのポジションを指定することなくReplicaサーバは新規Masterからのレプリケーションを継続できる
* 新規Replicaサーバの構築時にもbinlogファイルとそのポジションを指定する必要がない

GTIDの詳細は以下の公式ドキュメントを参照ください。

https://dev.mysql.com/doc/refman/8.0/en/replication-gtids.html

本記事ではAurora MySQLクラスター間のbinlogレプリケーションを扱いますが、Source側AuroraクラスターでのMaster(Writer)インスタンスのフェイルオーバーが発生しても基本的にAuroraクラスターにて新規インスタンスは同じbinlog情報を持つと考えられるため、GTIDの恩恵が大きいと言えない部分がありそうです。[^1]

[^1]: Aurora(RDS)クラスターでのWriter/Readerインスタンスのbinlogファイルの一貫性について筆者は確認できていません

以下のAWS側のドキュメントでも、

> You typically use GTID-based replication with Aurora when replicating from an external MySQL-compatible database into an Aurora cluster.

とあり、Source側がオンプレミスのMySQLのDBにてGTIDのレプリケーションにしておけばオンプレミスでのフェイルオーバー発生時の運用が改善されると述べられています。

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/mysql-replication-gtid.html

また、GTIDでのレプリケーションの場合のデメリットとして、一部のレプリケーションをスキップさせたい等のbinlogポジションを指定する細かな設定ができなくなる、というものがありますがそういった要件は無い前提とします。

これらのことを考慮しつつ本記事ではGTIDを採用したレプリケーション構築を行います。

# 構築 of Aurora MySQLクラスター間のbinlogレプリケーション

## Step1: レプリケーションSourceとなるMySQLクラスターに設定されているパラメータグループの値を変更

新規作成したパラメータグループにて以下のパラメーターで設定する。

|Parameter|Value|
|-------|------|
|gtid-mode|ON|
|enforce_gtid_consistency|ON|
|binlog_format|MIXED|

:::note warn
上記のパラメータはすべて "Apply Type" が "Static" であり、パラメータ値の変更を適用させるにはRDSインスタンスを再起動する必要があります。
:::


## Step2: SourceとなるMySQLクラスターからTargetとなるクラスターをClone

AWSコンソール上から作成する場合は以下の画像のようにクラスター設定の"Actions"から"Create clone"を選択し、各種設定をする。

:::note info
IaCでリソースを管理している場合はCloneの作成は各種IaCツールから作成してください。
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/8e01b2c3-a616-d4c7-68f5-997ea0bbac60.png)

### Step3: CloneされたTargetのクラスターのWriterインスタンスのLogからBinlogポジションを確認する

前Stepにて、CloneされたTargetクラスターのRDSのWriterインスタンスのLogにてBinlogポジションが以下画像のように出力されているので、これをメモしておきます。

このBinlogポジションは後述のStepでの初回レプリケーション作成にて必要になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/e9fc9bb1-f3cb-0837-1d89-07a53d01e79f.png)

## Step4: AWS側にてTarget側クラスターからSource側クラスターへMySQL接続できるようにサブネット/セキュリティグループを設定する

binlogレプリケーションではTarget側からSource側へ接続するので、そのためのクラウド側の設定をする必要があります。

各クラスターが持つサブネット間のルート設定とセキュリティグループ設定を確認してください。

設定の詳細はこの記事では割愛します。

## Step5 (Optional) Source側にてbinlogレプリケーションの保持期間を設定する

:::note info
レプリ対象データのサイズに応じて初回レプリケーションの時間がかかります。
Aurora MySQLではbinlogファイルに直接アクセスができないので、初回レプリケーション時のレプリケーションにてbinlogファイルが消える前に設定できるように、必要に応じて保持期間を延ばす設定をしておきましょう。

参照: [To retain binary logs on an Aurora MySQL DB cluster](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.MySQL.SettingUp.html#:~:text=To%20retain%20binary%20logs%20on%20an%20Aurora%20MySQL%20DB%20cluster)
:::

Source側のMySQLにログインし以下コマンドにてレプリケーションの保持期間を延ばしておきます。

```sql:144時間(6日間)binlogファイルを保持する設定コマンド
mysql> CALL mysql.rds_set_configuration('binlog retention hours', 144);
```

Aurora MySQLはデフォルトで`24`(1day)に設定されています。

## Step6: Source側にレプリケーション用ユーザーの作成および権限付与

Source側にて レプリカターゲットからレプリカソースに接続してレプリケーションを実行するためのユーザーを作成します。

Source側のMySQLにログインし以下コマンドを実行します。

:::note info
* ユーザー名とパスワードは任意で設定可能です
* SSL設定は要件に応じて設定してください
:::

```sql:レプリケーション用ユーザー作成
mysql> CREATE USER 'rpl'@'%' IDENTIFIED BY 'Passw0rd';
```

```sql:作成したレプリケーションに権限付与
mysql> GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'rpl'@'%';
```

## Step7: Target側にてレプリケーション設定をする

Target側MySQLにログインし、以下の内容を[rds_set_external_source](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/mysql-stored-proc-replicating.html#mysql_rds_set_external_source)のプロシージャに設定し実行する

* 以前のStepで確認したBinlogファイル名とポジション
* レプリケーション用ユーザーとパスワード
* ソース側ホスト名

```sql:レプリケーション設定
mysql> CALL mysql.rds_set_external_source (
  'source_host',
  3306,
  'rpl',
  'Passw0rd',
  'mysql-bin-changelog.000002',
  772,
  0
);
```

## Step8: (Optional) Target側にて必要に応じてレプリケーションのフィルタリング設定をする

レプリケーションの対象のテーブルを指定する要件がある場合はTarget側パラメータグループの値を設定します。

パラメータ値は以下のAWS公式ドキュメントに記載されているので、こちらを参照ください。

https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.Filters.html

これらのパラメータ値は"Dynamic"設定なのでレプリケーションを停止させている状態で設定し、レプリケーションを再開させることで適用されるようになります。

## Step9: Target側にてレプリケーションを開始する

Target側MySQLにログインし、[rds_start_replication](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/mysql-stored-proc-replicating.html#mysql_rds_start_replication)のプロシージャでレプリケーションを開始します。

```sql:レプリケーションの開始
mysql> CALL mysql.rds_start_replication;
```

レプリケーションが成功しているか`SHOW REPLICA STATUS`にて`Last_Errno: 0`になっているか確認します。


```sql
mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
                  Source_Host: source_host
                  Source_User: rpl
                  Source_Port: 3306
                Connect_Retry: 60
              Source_Log_File: mysql-bin-changelog.000023
          Read_Source_Log_Pos: 94329298
               Relay_Log_File: relaylog.000002
                Relay_Log_Pos: 336
        Relay_Source_Log_File: mysql-bin-changelog.000023
           Replica_IO_Running: Yes
          Replica_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table: mysql.%
                   Last_Errno: 0
```

## Step10: GTIDのレプリケーションで開始しなおす

`SHOW REPLICA STATUS`にて`Executed_Gtid_Set`に値があることを確認しましょう。

```
Executed_Gtid_Set: xxxx-xxxx-xxxx-xxxx-xxxx:1-1690
```

GTIDのレプリケーションを開始前に既存のレプリケーションを[rds_stop_replication](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/mysql-stored-proc-replicating.html#mysql_rds_stop_replication)のストアドで停止します。

```sql:レプリケーションの停止
mysql> CALL mysql.rds_stop_replication;
```

GTIDを使ったレプリケーション設定を[rds_set_external_source_with_auto_position](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/mysql-stored-proc-replicating.html#mysql_rds_set_external_source_with_auto_position)ストアドで設定します。

```sql:GTIDレプリケーション設定
CALL mysql.rds_set_external_source_with_auto_position (
  'source_host'
  , 3306
  , 'rpl'
  , 'Passw0rd'
  , 0
);
```

レプリケーションを再開します。

```sql:レプリケーションの開始
mysql> CALL mysql.rds_start_replication;
```

`SHOW REPLICA STATUS`にて`Auto_Position: 1`が設定されていれば、GTIDでのレプリケーションが実施できています。

```
Auto_Position: 1
```

# Source側でのフェイルオーバー検証

上述の"GTIDについて"の章にて、Auroraクラスター間のレプリケーションではGTIDの恩恵は直接無い前提ですが、運用検証としてSource側のAuroraクラスターにてフェイルオーバーを発生させてレプリケーションに問題が生じないかを確認します。

フェイルオーバー実行前のレプリケーション状況を確認

```sql
mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
.....
              Source_Log_File: mysql-bin-changelog.000023
          Read_Source_Log_Pos: 94330102
.....
                   Last_Errno: 0
                   Last_Error:
.....
```

AWSコンソール上からSource側のフェイルオーバーを実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/8d671fd8-7417-4a22-444b-29a0ce8220f4.png)

フェイルオーバーが完了したことを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91562/6dbd1d58-9959-9d62-fc5c-0a9ea2c00b7d.png)

binlogポジションが前進しているが、エラー無し。

```sql
mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
.....
              Source_Log_File: mysql-bin-changelog.000024
          Read_Source_Log_Pos: 197
.....
                   Last_Errno: 0
                   Last_Error:
.....
```

Source側でデータをインサートする
→ 問題なくTarget側にレプリケーションされることを確認

binlogポジションが前進していることを確認

```sql
mysql> SHOW REPLICA STATUS\G
*************************** 1. row ***************************
             Replica_IO_State: Waiting for source to send event
.....
              Source_Log_File: mysql-bin-changelog.000024
          Read_Source_Log_Pos: 599
.....
                   Last_Errno: 0
                   Last_Error:
.....
```

# 参考

* https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Replication.MySQL.SettingUp.html