今更ながら「Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases」 を読んで調べたことのメモ

Auroraのアーキテクチャとその設計上の考慮事項について書かれている論文が 2017 年に公開されている。有名なのでその時読まれた方も多いと思う。私はその時 Aurora を触ってなくて存在を知っていただけだったので今更ながら目を通してみた。

自分には結構難しくて理解が合っているかどうかはわからないし2022年の今とは変わっているところもあるのかもしれないけど一応読んで色々調べたりしたことを残しておく。

THE LOG IS THE DATABASE なアーキテクチャ

論文にTHE LOG IS THE DATABASEと書かれている。多くの機能がRedoログを要としている気がする。 Aurora のアーキテクチャAWS の基盤に最適化されているような形になっているように思われる。

前提として、もう当たり前のことではあるが、AWS は1つのリージョンに、複数の「AZ(Availability Zone)」という、物理的に異なるとされる論理的に異なる単位を持っている。物理的に完全に別な場所にあるのか、内部的に何らかで分離されているのかはわからないが、1つの AZ レベルの障害が、他のAZには影響を及ばさないような形にはなっていると思われる。

Auroraでクラスターを組む時、インスタンスはプライマリとレプリカをAZを跨いで配置することができる。というか可用性を考えると大抵はこういう配置にすることになると思う。

通常のRDSでも複数のインスタンスをAZを跨いで起動することになると思うが、この時、通常のRDSであればレプリケーション時のバイナリログ等の多くのデータがネットワーク経由でプライマリからレプリカへ送られるのに対して、Auroraの場合はRedoログのみが送られる。(Redoログは「ページへの行の追加や更新、分割やマージなどのMTR(ミニトランザクション)レベルの細かい変更ログで、これを再実行することで同じ操作を再現できるもの」といった感じで理解している) これによってAZを跨がるインスタンス間のデータ同期の際のネットワークボトルネックを削減している。

また、CPU・メモリといったコンピューティングリソースと、ストレージ基盤を分離した構成としている。これ自体はオンプレミスであれば共有ストレージを用いた構成と似たような感じかと思っている。 Auroraのストレージ基盤がどうなっているのかはわからないが、データを書き込む際は Protection Groups と呼ばれる 10 GB の論理的なブロック単位で、AZをまたいで6つのストレージ基盤用のノードに配置しているらしい。

ストレージ基盤に送られるのもRedoログのみのようで、これも6つのノードに保存される模様(論文には書かれてないが実際には6つのコピーは全て同一ではなく、3 つはフルセグメント(データページとログレコード)、残りにの3つはテールセグメント(ログレコードのみ)らしい)。 Redoログには様々な種類のLSN(Log Sequence Number)という番号が振られており、これらを用いて、Auroraの各ストレージノードがどこまで変更を反映できているかを把握する。

書き込み時はこの6つのノードにリクエストし、内4つまで書き込みができれば、書き込み完了とみなされる。これは AZ 全体の障害に加えてさらに1ノードの障害でも耐えうるものにするためであるとのこと。 読み込み時は6つのノードにリクエストし、3つのノードから結果が返されればOKとなる。ただし、読み込みクォーラムを実際に使用するのは、プライマリDBインスタンスのキャッシュの喪失・再起動、レプリカのプライマリへの昇格などローカルの状態再構築、破損したセグメントの再構築、クォーラムの修復といった場合で、それ以外は予め管理している必要なデータバージョンをもつノードから読み取る。

データの読み込み時、バッファキャッシュを見に行き、キャッシュに存在しない場合はストレージIOリクエストが発生する。 バッファキャッシュがいっぱいの場合、通常であれば持っているページがダーティページ(ストレージに書き込むべき内容)であった場合、捨てる前にストレージに書き込みされるが、Auroraだとストレージに書き込まずに捨てる。この時ページLSNというものがVDL以上の場合、ページをキャッシュから削除することになるらしい。こうなると、ストレージ側が古い情報のままになるが、すぐにRedoログから最新の情報に更新し、ストレージ側の情報をインスタンス側へ反映するらしい。 Protection Group ごとに最小読み取り Protection Group Min Read Point LSN (PGMRPL)をいつでも計算でき、すべてのノード間でゴシップを実行し、保護グループの Protection Group Min Read Point LSN を「最低水準点」として設定される。

クラッシュリカバリ時もRedoログを有効に活用するようになっている。REDOログアプリケーターがデータベースから切り離され、ストレージノードで並行して、常にバックグラウンドで動作するため、処理コストを少なく実現できるらしい。読み込みクォーラムはここで使われる。 データベースは、すべてのProtection Group に対して読み取りクォーラムを確立すると、VDL(Volume Durable LSN: VCLより小さいが最も大きいCPL)を再計算し、新しいVDL以降のすべてのログレコードを削除する切り捨て範囲を生成して不要なVDLを計算する。

まとめ

Aurora の設計に関する論文を読んで調べたことをまとめた。 AWSの基盤に合わせて、コンピューティングノードとストレージノードを分離し、Redoログをベースにしてのプライマリインスタンス・レプリカインスタンス間や、各インスタンスとストレージノード間のネットワーク通信や、ストレージIOなどの一般的に遅くなる部分を減らし、ストレージノード等のCPUリソースをうまく活用できる感じの構成になっていると思われた。 Redoログでは、様々なLSNを活用し、Write/Read/Commit/Recoveryなどを高速かつ安全に行えるような仕組みを実現しているようだが、各LSNの扱いをまだあんまり理解できていないので、また調べてわかったら更新したい。

参考