年中アイス

いろいろつらつら

Fault Injectionを使ったAurora MySQLの任意のレプリケーション遅延

Aurora MySQLでReaderへの反映が遅延した場合の挙動をテストするために遅延発生方法を調べたのでメモ。Aurora 2.10.3 (MySQL5.7互換)で行いました。

Fault Injection

Fault InjectionのReplica Failureを使うことで任意の時間レプリケーションを遅延させることができます。

ALTER SYSTEM SIMULATE percentage_of_failure PERCENT READ REPLICA FAILURE
  [ TO ALL | TO "replica name" ]
  FOR INTERVAL quantity { YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND };

これは一時的なものでFOR INTERVALの時間が経過すると解除されます。以下のSQLで、「Writerから全てのReaderへの変更を100%、実行後15秒間ブロックする」という障害の擬似再現になります。

ALTER SYSTEM SIMULATE 100 PERCENT READ REPLICA FAILURE TO ALL FOR INTERVAL 15 SECOND;

これをWriterで実行した後、Writerでテーブルのレコード追加や変更を行なっても15秒間はReader側には反映されません。Reader側も止まるわけではなくクエリを実行して結果を取得することはできますが、データ反映が遅延します。*1

100の部分を変えることで何%にFailureを発生させるか、TO ALLの部分にReader名を指定することで任意のReaderに限定して発生させることもできるそうです。

ドキュメントの注意事項にもありますが、遅延時間は長く指定することも可能ですがWriterの書き込み量(データサイズ?)によってはReaderがクラッシュしたと判断してインスタンスが置き換えられる状況に陥るようなのでWriteがそれなりにある環境だと遅延だけで済まない状況になる点は注意が必要です。

Take care when specifying the time interval for your Aurora Replica failure event. If you specify too long of a time interval, and your writer instance writes a large amount of data during the failure event, then your Aurora DB cluster might assume that your Aurora Replica has crashed and replace it.

MySQL Delayed Replicationとの違い

Failt Injectionを使うと任意の時間、任意のReaderや一部遅延など障害らしい挙動が起こせますが、常時一定時間遅延させることはできません。常時遅延させる必要がある場合はbinlogレプリケーション+MASTER_DELAYの指定を試す必要があります。

MySQLには遅延レプリケーション(Delayed Replication)という仕組みがあり、これはReader側でCHANGE MASTER TO MASTER_DELAY = Nを設定することでN秒遅延するレプリケーションが構成可能です。意図的に遅延させることで誤ったデータ破壊(DROP TABLEやDELETE ALLのようなオペミスや条件ミスでの実行など)が起きた場合に復帰時間を短縮できるように使うケースがあるようです。RDS MySQLはこの機能がマネージドで提供されているそうです。

Aurora MySQLは通常のMySQLと異なり、とても簡単に言うとストレージを共有してWriter/ReaderのVMをそこにかぶせる形になっています。*2

Aurora MySQLも通常のMySQLと同様にbinlogを出力し、それを使った遅延レプリケーションを組むことは自分でやればおそらく可能です。ただ全て手動で用意しないといけないため、それなりに手間がかかります。Auroraのメジャーバージョンアップ時にこのbinlogレプリケーション構成を使う最小限のダウンタイムによるアップグレードと言う記事が公式ブログで紹介されています。遅延レプリケーションは使っていないですが、この手順でbinlogレプリケーションを組んだ後にCHANGE MASTER TO MASTER_DELAY = Nを指定したらできると思います。*3

まとめ

今回はFault Injectionを使ってレプリケーション遅延を起こしてみました。構成やコードで何かしら遅延対策を入れていても実際に起きるまでそのテストができず、実際起きたらダメみたいなことはよくあるのでちゃんとテストしていきたいですね。

Fault Injectionのドキュメントを見ると、他にもインスタンス障害、ディスクエラー、ディスク輻輳が再現できるそうです。インスタンス障害は構成、ディスクは読み書きエラー発生テストとかでしょうか。

参考ページ

*1:ここ厳密にWriterからReaderへのリクエストをブロックという表現がレプリケーションのことだけかは読めません。

blocks all requests from the writer instance to an Aurora Replica or all Aurora Replicas in the DB cluster

*2:細かいところはAWSのドキュメント読んでください

*3:Auroraのアップグレードのためにこの構成を組んだことはありますが、遅延レプリケーションは試したことはないです。