はじめに
Aurora の特徴の一つには、プライマリインスタンスとレプリカでストレージを共有している点が挙げられます。
しかし、CloudWatch には「AuroraReplicaLag」というメトリクスが用意されています。「同じストレージを共有しているのになぜ遅延が起こるのか」という疑問が生じる人もいると思います。
実際、年末に質問があったので、調べてまとめてみました。
AuroraReplicaLag とは何か
AuroraReplicaLag のドキュメントを読むと、次のように説明されています。
Aurora レプリカについて、プライマリインスタンスからアップデートをレプリケートする際の遅延時間。
Auroraのデータは共有ストレージに書き込まれます。
リードレプリカは、更新を行うプライマリインスタンスからアップデートを受信して何をしていると思いますか?
答えはメモリー上のバッファープールの更新です。
プライマリインスタンスからREDOログを受信して、バッファープールを更新しています。
バッファープールとは
メモリー上のキャッシュ領域です。
しかし、ただのキャッシュではなく、キャッシュされた以降はこちらが主となります。
DBMS はデータを固定長のページ単位で管理しています。ページ内には複数の行が格納されています。
DBMS はクライアントのリクエストに応じて、ストレージからページをバッファープールに読み込みます。一度バッファープールに読み込まれたページは、それ以降はストレージにアクセスせず操作されます。これにより、同じデータに対するストレージへのリクエストが繁発しないようになるため、システム全体の性能が向上します。
バッファープールの更新が必要な理由
なぜ、バッファープールの更新が必要なのでしょうか。
それは、バッファープールにページが存在する場合、ストレージからの再読み込みを行わないからです。
Auroraの各ノードはストレージを共有していますが、インスタンスが異なるためメモリーは独立しています。このため、各ノードのバッファープールの状態は一致していません。
Auroraでプライマリインスタンスがデータを更新した時、もし同じページがレプリカのバッファープールにキャシュされていれば「更新前」の状態になっています。そして、このページはレプリカ側では再読み込みされません。この状況を解決するため、プライマリインスタンスはREDOログをレプリカに送り、レプリカはバッファープールを更新する必要があります。
この過程が実行されないと、レプリカでは以下のような問題が発生する可能性があります。
- 更新前のデータをクライアント返す
- 削除済みのデータをクライアントに返す
- 新規に挿入されたデータが認識されない
いわゆるレプリケーション遅延です。
新規に挿入されたデータが認識されないってどういうこと?
この中で「新規に挿入されたデータが認識されない」というのは奇異に感じるかも知れません。
新規データはレプリカにはキャッシュされていないように思われるからです。
データはページ単位で管理され、ページ内には複数の行が入っていることを思い出してください。新規データの登録されたページがバッファープールに格納されている場合は、ストレージを再読み込みしません。このため、新規データはストレージに存在しても認識されません。
まとめ
AuroraReplicaLag は、REDOログの同期遅延を監視するメトリクスです。
プライマリインスタンスとレプリカで、同じデータがバッファープールに格納されていた場合、レプリカのバッファープールが更新されないと新しいデータは参照可能になりません。
興味がわいたらこの論文を読むとことをおすすめします。Aurora に対する理解が深まりますよ。