RDS MySQL Multi-AZのクラス変更中にSQLコマンド実行しても大丈夫？

今回はお仕事の中でMulti-AZなRDS MySQLのクラス変更について調査＆問い合わせた結果わかったことです。
（ちなみに「わかった」ものの調査が遅きに失してお仕事には活かされず😅）

:::note warn
後述するRDS MySQL Multi-AZのクラス変更の処理の流れについては、調査＆問い合わせの結果を想像で補っている部分があります。RDS基盤の処理の詳細についてはAWS外部に開示不可のためです。
:::

# Background

Multi-AZでAmazon RDS MySQLのインスタンスを運用しているとします。
そしてそのインスタンスにクラス変更を行ったとします。
例えば、 `db.t3.medium` を `db.m5.large` に変更したり、 `db.m5.2xlarge`を `db.r7g.xlarge`に変更したり。

ご存知の通り、Multi-AZのRDSをクラス変更する場合、おおよそ次のようにことが進みます：

1. クラス変更の開始（AWS管理コンソールほか起動方法は複数あり）
1. スタンバイ側のクラス変更
1. フェールオーバー（スタンバイがプライマリに、プライマリがスタンバイに切り替わる） ※ここでダウンタイム発生 数十秒～数分
1. スタンバイ側（#3より前はプライマリだった側）のクラス変更
1. クラス変更の完了

絵的にすると・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/8c256879-25d7-10d0-fd26-741e174f64ac.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/ddf9d3e7-02d4-d218-a26e-d7e11ab77487.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/8ecbc6a3-9a07-5746-36a2-a93cd0b8cd16.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/e5debaff-4c8d-d397-9da5-d5a73497ac81.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/f7c5e66d-40f8-fad1-f552-6194b529d117.png)

このようなプロセスのおかげで、クライアントからデータベースへの接続のダウンタイムは最小限に抑えられます。

# Question

では、クラス変更の#2や#4の最中に当該インスタンスに対してSQLコマンド実行しても大丈夫なのでしょうか？　
ここで「大丈夫なのか？」とは、「プライマリ／スタンバイの間のデータ整合性が損なわれたり、クラス変更の処理過程に支障を来したりしないのだろうか？」ということです。

#2（左） や #4（右） の状態：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/3819d3b1-3a41-c16d-40da-da78121a15a5.png)

# Anwser

大丈夫。

なぜなら・・・
* Multi-AZなRDSインスタンスのクラス変更は前述の通り __常にスタンバイ側で__ 実行されます。
* そしてこのとき、プライマリ→スタンバイへの __データ同期は意図的に停止__ されています。
* 同期再開に備えて、__プライマリ側に加えられたデータの変更は記録__ されます（これはおそらくREDOログやWALのような仕組みと想像しています）。
* スタンバイのクラス変更が完了すると、フェールオーバーが始まります。
* まず __同期停止中のプライマリ側で行われた変更がスタンバイ側に送信__ されます。
* スタンバイ側でクラッシュリカバリが起動して、スタンバイ側に変更が反映されます。
* そしてプライマリとスタンバイが交代して、フェールオーバーが終わります。
* ・・・以下略。新スタンバイ側で同じようにクラス変更とクラッシュリカバリが行われ、データ同期が再開します。

絵的にすると・・・
まずはクラス変更開始前：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/0586fdcf-1bd4-18af-ea93-ecc90b254053.png)

クラス変更を開始すると同期が停止され、まずはスタンバイ側でクラス変更：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/4ce3f09e-f625-f0a3-3324-0b3c796cd02e.png)

フェールオーバーで、スタンバイ側に変更が反映され、RDSインスタンスのDNS名を名前解決した結果得られるIPがプライマリからスタンバイに変更：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/986e025d-5a78-1ea3-6435-95345c457b50.png)

引き続き、スタンバイ側（先程までプライマリだった側）でクラス変更：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/5e56cdb6-4d3d-67c8-e2db-df27d9fddde8.png)

スタンバイ側（先程までプライマリだった側）でクラッシュリカバリ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/e10b5eb7-7305-e6c8-d707-aadc3519e86e.png)

最後に、同期レプリケーション再開：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/42e48086-313a-bdeb-8dbc-7d6c3248e9e2.png)

なるほど。意図的な同期停止、停止中の変更の記録、そしてそれを用いたクラッシュリカバリ。
これならSQLコマンドからクラス変更中のスタンバイを守り、しかもSQLコマンドによる変更をスタンバイに完全に反映できます。

このような次第で、 __SQLによるデータベース内の変更操作はDMLによるものであれDDLによるものであれ、クラス変更操作と競合しない形で、プライマリ→スタンバイへと完全に反映__ されます。

# 参考記事


Amazon RDS よくある質問 の[マルチ AZ 配置](https://aws.amazon.com/jp/rds/faqs/#Multi-AZ_Deployments)の「マルチ AZ のフェイルオーバー中どのようなことが起こるのですか? またこれはどれくらいの間継続するのですか?」

> フェイルオーバーの際には、Amazon RDS は単純に DB インスタンスの正規名レコード (CNAME) を反転させ、スタンバイをポイントします。そしてこのスタンバイが今度は新しいプライマリになります。（・・・中略・・・）フェイルオーバーは、プライマリで障害が検出されてからスタンバイでトランザクションが再開されるまでの間隔として定義され、通常 1 ～ 2 分以内に完了します。コミットされていない大きなトランザクションを回復させる必要があるかどうかによっても、フェイルオーバー時間は異なります。

AWS re:Post の[マルチ AZ 配置は、Amazon RDS MySQL の変更中のダウンタイムを削減するのに役立ちますか?](https://repost.aws/ja/knowledge-center/rds-mysql-downtime-impact)の「DB インスタンスクラスの更新」

> インスタンスクラスの変更には新たに定義されたハードウェアセットが必要であり、この変更はオンラインのオペレーションではないため、ダウンタイムが必要になります。Amazon RDS MySQL DB インスタンスのマルチ AZ 配置により、どのような影響も大幅に緩和できます。これは、更新がプライマリとスタンバイに対して同時に行われないためです。スタンバイインスタンスが最初に変更され、フェイルオーバーが発生します。フェイルオーバー後、新しいスタンバイが変更されます。必要なダウンタイムには、フェイルオーバーの完了 (通常は 60～120 秒) と DB エンジンのクラッシュリカバリの完了の時間が含まれます。詳細については、「マルチ AZ 配置」を参照してください。

Amazon Web Services ブログの[Amazon RDS Under the Hood: Multi-AZ](https://aws.amazon.com/jp/blogs/news/amazon-rds-under-the-hood-multi-az/)の「接続に関する問題と同期」

> 問題または意図的な管理アクションのために、プライマリインスタンスとスタンバイインスタンスが相互に接続されていない場合があります。（・・・中略・・・）接続が復元した後、通常の進行中のレプリケーション状態に戻る前に、ボリュームの再同期を行う必要があります。
> 
> 再同期プロセスにより、データの両方のコピーが一貫した状態に復元されます。再同期に必要な時間を短縮するために、プライマリは2つのインスタンスが切断されている間に変更されたブロックを追跡します。再同期が発生すると、それらの変更のみをプライマリインスタンスからスタンバイインスタンスに送信するだけでよく、プロセスが高速化されています。