mita2 database life

主にMySQLに関するメモです

Amazon Aurora レプリカ では metadata lock 待ちが発生しない

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

比較をわかりやすくするため、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 を実行してみる。

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 で試している