Amazon Aurora のレプリカは Vanilla MySQL のレプリケーションとは違った仕組みで実現されている。 マスターとレプリカは同じディスクボリュームを参照しており、マスターでの更新はほぼ即時レプリカに反映される。
DB クラスターボリュームは DB クラスターのデータの複数のコピーで構成されます。ただし、クラスターボリュームのデータは、DB クラスターのプライマリインスタンスおよび Aurora レプリカの 1 つの論理ボリュームとして表されます。この結果、すべての Aurora レプリカは、最短のレプリカラグでクエリの結果として同じデータを返します。 レプリカラグは、通常はプライマリインスタンスが更新を書き込んだ後、100 ミリ秒未満です。https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/Aurora.Replication.html
テーブル定義の変更もすぐにレプリカに反映されるのか?
仕組みから考えると、DDL (CREATE/DROP/ALTER/TRUNCATE) もレプリカに即時反映されそうだが、どうだろうか。
以下のように、マスターとレプリカでカラム数を定期的に数えるシェルを回しながら、ADD COLUMN
を実行して確認してみた*1。
while [ 1 ] do sleep 1 date echo "COLUMN at MASTER $(mysql -uadmin -h <マスター> -e 'desc sbtest.sbtest1' | wc -l)" echo "COLUMN at REPLICA $(mysql -uadmin -h <レプリカ> -e 'desc sbtest.sbtest1' | wc -l)" done
- RDS MySQL
比較をわかりやすくするため、Vanilla MySQL (RDS MySQLを利用) の挙動から。MySQL では、ALTER文がレプリカで再実行されるため、マスターでかかった時間と同じぐらい時間がかかる。 そのため、時間のかかるALTER文だと大きなレプリケーション遅延が発生する。この検証ではマスターから23秒遅れでレプリカに反映されている。
Mon Jul 20 06:39:59 UTC 2020 COLUMN at MASTER 5 COLUMN at REPLICA 5 <snip> Mon Jul 20 06:40:21 UTC 2020 COLUMN at MASTER 5 COLUMN at REPLICA 5 Mon Jul 20 06:40:22 UTC 2020 COLUMN at MASTER 6 COLUMN at REPLICA 5 <snip> Mon Jul 20 06:40:44 UTC 2020 COLUMN at MASTER 6 COLUMN at REPLICA 5 Mon Jul 20 06:40:45 UTC 2020 COLUMN at MASTER 6 COLUMN at REPLICA 6
- Aurora
一方、Aurora はほぼ同時にレプリカへのカラム追加が完了している。
$ sh check.sh Mon Jul 20 05:50:26 UTC 2020 COLUMN at MASTER 7 COLUMN at REPLICA 7 <snip> Mon Jul 20 05:51:14 UTC 2020 COLUMN at MASTER 7 COLUMN at REPLICA 7 Mon Jul 20 05:51:15 UTC 2020 COLUMN at MASTER 8 COLUMN at REPLICA 8
テーブル定義の変更もAuroraではすぐレプリカに反映されることが確かめられた。
ALTERの対象テーブルへ実行中のクエリがあったら?
次は、metadata lock
まわりの挙動を確認してみる。
マスター
Aurora マスターの挙動は、Vanilla MySQL と変わらない。実行中のクエリがあった場合、そのクエリが終わるまで、metadata lock
獲得待ちとなり、ALTERが待機する(Waiting for table metadata lock
)。そしてさらに後続のクエリも metadata lock
待ちで待機する。
mysql> SHOW PROCESSLIST; +-----+~+---------------------------------+------------------------------------+ | Id |~| State | Info | +-----+~+---------------------------------+------------------------------------+ <snip> | 263 |~| User sleep| SELECT *, SLEEP(120) FROM sbtest.sbtest1 LIMIT 1 | | 264 |~| Waiting for table metadata lock | alter table sbtest.sbtest1 add column (cx int default 1) | | 265 |~| init | SHOW PROCESSLIST | +-----+-~-+---------------------------------+----------------------------------+ 7 rows in set (0.00 sec)
レプリカ
レプリカで SELECT *, sleep(240) FROM sbtest.sbtest1 LIMIT 1
を実行しながら、マスターに対して、ALTER TABLE sbtest.sbtest1 ADD COLUMN
を実行してみる。
- RDS MySQL
Applier Thread (SQLスレッド) が、先行するクエリが終わるまで、metadata lock
獲得待ちで待機する。
マスターと同じ挙動がレプリカで再現する。
mysql> show slave status \G *************************** 1. row *************************** <snip> Slave_SQL_Running_State: Waiting for table metadata lock Master_Retry_Count: 86400
- Aurora
マスターでALTERを打ったタイミングで、レプリカで対象テーブルに対して実行中のクエリはエラーになった。 ALTERを打ったその瞬間に実行中だったクエリがエラーになるだけで、その後はALTER実行中であっても問題なくSELECTができる。
mysql> SELECT *, sleep(240) FROM sbtest.sbtest1 LIMIT 1; ERROR 2013 (HY000): Lost connection to MySQL server during query
そして、マスターでALTERが完了した直後もレプリカで実行中のクエリがエラーになった。実行中のクエリがエラーで強制終了させられるので、レプリカ側で Vanilla MySQL のように metadata lock
獲得待ちになることはなさそう。
mysql> SELECT *, sleep(240) FROM sbtest.sbtest1 LIMIT 1; ERROR 2013 (HY000): Lost connection to MySQL server during query
まとめると、ALTERの開始時と完了時にレプリカで実行中のクエリがエラーになるようだ(そのおかげで、レプリカで metadata lock
獲得待ちが発生しない)。
まとめ
- Aurora では、DDLはレプリカにすぐ反映される
- Aurora では、レプリカでの
metadata lock
待ちは気にしなくてよさそう- しかし、ALTER実行によりレプリカでクエリが単発レベルのエラーになることはある
*1:v5.6 で試している