Amazon RDS MySQL から Aurora に移行する手順

Amazon Web Services RDS の MySQL から Aurora へ移行する手順をまとめる。

## Auroraのパラメーター・グループを作成

事前に、Auroraのインスタンスに適用するパラメーター・グループを作成する。

以下はパラメーターの例であり、移行に必要というわけではない。各環境に応じて必要な設定を行う。

Node
- innodb_lock_wait_timeout: 10
- max_connect_errors: 18446744073709547520
- slow_query_log: 1
- long_query_time: 1
- wait_timeout: 90
- thread_cache_size: {DBInstanceClassMemory/104857600}

Cluster
- character_set_client: utf8mb4
- character_set_connection: utf8mb4
- character_set_database: utf8mb4
- character_set_results: utf8mb4
- character_set_server: utf8mb4
- skip-character-set-client-handshake: 1


## MySQLのリードレプリカの作成

MySQLのリードレプリカ(スレーブ)を作成する。

このリードレプリカのスナップショットが、後に Aurora を起動する際のベースラインとなる。

なお、Multi AZ でない場合、I/Oの1分程度の停止が発生する。Multi AZ の場合は、マスターは停止しない(スタンバイからスナップショットがとられる)。

また、リードレプリカを作ることで、マスターのバイナリログが、レプリケーションが追いつくまで保持されたままになる（標準では、RDSはバイナリログを出来るだけ早くS3に退避して削除してしまう）。

コンソール
- コンソールで、[RDS] > [DB Instances] > 対象のインスタンスを選択する
- Instance Actions から Create Read Replica を選択する

設定
- DB Instance Class: マスターと同じ (レプリケーションのWriteのみなので、少し下でも大丈夫かも？)
- Storage Type: General Purpose SSD (マスターと同じ)
- Read Replica Source: 対象のインスタンス
- DB Instance Identifier: 任意のもの (例：najeira-replica)
- Destination Region: マスターと同じ
- Destination DB Subnet Group: default
- Publicly Accessible: No
- Availability Zone: No Preference
- Database Port: 3306
- Copy Tags To Snapshots: No
- Enable Enhanced Monitoring: No
- Auto Minor Version Upgrade: Yes


## MySQLのリードレプリカのレプリケーションの停止

スナップショットを得るために、リードレプリカのレプリケーションを停止する。

リードレプリカにログインする。

```
mysql -h hoge.fuga.ap-northeast-1.rds.amazonaws.com -u username -p
```

> 間違えてマスターにログインしないように

レプリケーションを停止する。

```
mysql> CALL mysql.rds_stop_replication;
+---------------------------+
| Message                   |
+---------------------------+
| Slave is down or disabled |
+---------------------------+
1 row in set (1.03 sec)

Query OK, 0 rows affected (1.03 sec)
```

なお、このあとでコンソールから状態を見ると以下のようになっている。
- Replication State: stopped
- Replication Error: Replication has been stopped by the rds_stop_replication stored procedure.  Use rds_start_replication to resume replication.

続いて、後にAuroraでレプリケーションを開始するときのために必要な値を記録しておく。

```
SHOW SLAVE STATUS \G
...
        Relay_Master_Log_File: mysql-bin-changelog.184682
...
          Exec_Master_Log_Pos: 422
...
1 row in set (0.00 sec)
```

以下の値を記録しておく。
- Relay_Master_Log_File: バイナリログファイルの名前
- Exec_Master_Log_Pos: ログファイルの場所


## MySQLのリードレプリカのスナップショットの取得

- コンソールで、[RDS] > [DB Instances] > 対象のインスタンスを選択する
- Instance Actions から Take DB Snapshot を選択する
- Snapshot Name を入力する (例：najeira-replica-160707)
- Yes, Take Snapshot を選択する

Rel: https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_CreateSnapshot.html

Memo: 数時間ほどかかる場合もある。普段のバックアップの時間から推測できる。

## Auroraの起動

リードレプリカのスナップショットからAuroraを起動する。
- コンソールで、[RDS] > [Snapshots] > 対象のスナップショットを選択する
- [Migrate Database] を選択する

以下のように設定する。
- DB Instance Class: 
- DB Instance Identifier: 任意のもの (例：najeira-aurora)
- VPC: Default VPC
- Subnet Group: default
- Publicly Accessible: No
- Availability Zone: No Preference
- Database Port: 3306
- Enable Encryption: No
- Auto Minor Version Upgrade: Yes

[Migrate] ボタンを押すことでスナップショットからAuroraが起動する。

Rel: https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Aurora.Migrate.html

Memo: ストレージ3TB(実データ700GB)のスナップショットから `db.r3.4xlarge` を起動するのに8時間ほどかかった

## Auroraの設定

パラメーター・グループとセキュリティ・グループを選択する。

セキュリティ・グループはMySQLと同じでよい。
パラメーター・グループは MySQL とは別の Aurora 用のものを作っておく。

Reboot し、パラメーター・グループが反映されるようにする。


## Auroraのレプリケーションを開始

`mysql.rds_set_external_master` コマンドで MySQL をマスターに、Aurora をスレーブに設定する。

```
mysql> call mysql.rds_set_external_master(
  'hoge.fuga.ap-northeast-1.rds.amazonaws.com', 
  3306, 
  "username", 
  "password",
  "mysql-bin-changelog.184682", 
  422, 
  0);
```

`mysql.rds_start_replication` コマンドでレプリケーションを開始する。

```
mysql> call mysql.rds_start_replication;
```

スレーブの状態を確認する。

```
mysql> SHOW SLAVE STATUS \G
```

`Exec_Master_Log_Pos` の値がメモしていたポジションから進んでいるようであれば、レプリケーションは開始している。

以下のようになっていればレプリケーションは開始している。

```
               Slave_IO_State: Waiting for master to send event
...
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
        Seconds_Behind_Master: 123
      Slave_SQL_Running_State: ...
```

なお、マスターに接続できない場合は以下のようなエラーが出力される。

```
               Last_SQL_Errno: 1045
                Last_IO_Error: error connecting to master 'username@hoge.fuga.ap-northeast-1.rds.amazonaws.com:3306' - retry-time: 60  retries: 1
```

セキュリティグループの設定で接続できない場合は以下のようになる。

```
               Slave_IO_State: Connecting to master
...
             Slave_IO_Running: Connecting
            Slave_SQL_Running: Yes
...
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
```


## アプリケーションの設定ファイルを準備

この時点で Aurora の Instance Endpoint が分かっているので、アプリケーションの接続先を Aurora にするために、設定ファイル等の準備をしておく。

## Auroraのレプリケーションが追いつくのを待つ

Seconds_Behind_Master の値を見つつ、レプリケーションが追いつくのを待つ。

Memo: バックアップと起動あわせて11時間ほどかかったので、そのタイムラグを追いつくのに8時間ほどかかった

## サービスをメンテナンスに設定

バックグラウンドのタスクなど、停止してもユーザーに影響が小さいものを先に停止する。

その後、例えば以下のようにしてメンテナンス状態とする。
- nginx で 503 を返すように設定
- アプリケーションのプロセスを停止

なお、スマホアプリは 503 を受け取るとメンテナンス表示を行うなどの対応がされていると良い。


## MySQLを読み取り専用に設定

MySQLのパラメーターグループの `read_only` を `1` に設定する。このパラメーターは即時に反映されるので、この時点で書き込みできなくなる。


## 逆方向のレプリケーション？

Aurora をマスター、MySQL をスレーブとする、いままでと逆方向のレプリケーションを設定すると、事故った時に MySQL 側に切り戻せるが、今回は割愛する。


## アプリケーションの接続先をAuroraに変更

設定ファイルなどのエンドポイントを変更してプロセスを再起動するなど、アプリケーションが新しい接続先を使うようにする。

まだこの時点では Aurora はスレーブであり、書き込みできないので書き込みが必要なクエリはエラーとなる。

## Auroraのレプリケーションを確認

マスターに追いついたことを確認する。


## Auroraのレプリケーションを停止

Auroraをマスターに昇格させるため、レプリケーションを停止する。

```
mysql> call mysql.rds_reset_external_master;
```

スレーブでなくなると、書き込みが可能になる(`read_only`が`IfReplica`なので)。


## サーバ側で動作を確認

アプリケーションの機能が動作することを確認する。
サーバ側で API を使ってみてエラーなどが発生しないことを確認する。


## サービスのメンテナンスを解除

nginx の 503 を応答する設定を解除する。


## アプリ側で動作を確認

アプリを使ってみてエラーなどが発生しないことを確認する。
この時、書き込みを伴う操作を実行すること。


## MySQLの停止

様子を見た後、問題がなければMySQLのマスターとリードレプリカを終了する。