先日公開された『Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases』を読みました。
興味深かった部分や疑問に思った(あんまりわかってない)部分をまとめておきます。
AWS は詳しくないので、ところどころ間違っているかもしれません。
Amazon Aurora とは
Amazon Aurora は Amazon Web Service が提供する、マネージドリレーショナルデータベースサービスです。
Amazon Aurora (MySQL 互換のリレーショナルデータベース) | AWS
Amazon Aurora のアーキテクチャ全体像
Aurora はデータベース層とストレージ層を分離した構成となっています。
データベース層は単一のプライマリデータベースと複数のリードレプリカから構成され、クエリの処理やトランザクションなどを担当します。
ストレージ層は redo ログやデータを保持し、また redo ログの適用やリペアのような処理も行います。
この記事では quorum、データのセグメント化、ネットワーク通信コストを下げる工夫を紹介しつつ、疑問に思った点などを付記していきます。
quorum
Aurora のストレージ層はレプリケーションと quorum により、十分な永続性と可用性を両立しています。
quorum システムはあるオペレーションが適用されるプロセス集合と別のオペレーションが適用されるプロセス集合が、必ず共通部分集合を持つように設計されたシステムです。
可用性を上げつつ、読み込みオペレーションを実行するレプリカ群の中に、最後に書き込みが行われたプロセス群が絶対含まれるようにしたい、といった要求に応えます。
quorum そのものについては『最近よく聞くQuorumは過半数(多数決)よりも一般的でパワフルな概念だった - Qiita』がわかりやすいです。
Aurora のデータは、3つの Availavility Zone にそれぞれ2つずつ、合計6つ複製されます。
それに対し、読み込み時は3つ(ただし正常時はデータベースインスタンスが in-sync なストレージノードを把握しているので、1つでよい)の、書き込み時は4つのストレージノードへ問い合わせることで quorum を形成します。
この構成により、プライマリデータベースの一貫性、高い書き込み可用性、すごく高い永続性・読み込み可用性が提供されます。
まず書き込み quorum が4であるため、任意の2ノードがダウンしたときの書き込み可用性、任意の3ノードがダウンしたときの永続性が保証されます。
これは Availability Zone 障害が発生しても更新処理が可能なこと、AZ 障害に加えディスクの故障などによりさらに1つのノードが故障(AZ + 1障害)してもデータロストしないことを意味します。
また読み込み quorum が3であるため、任意の3ノードがダウンした場合でも読み込みは成功します。
そのため AZ + 1 障害が発生しても、読み込みは継続することができます。
AWS のような大規模環境クラウド環境において、何かが壊れているというのは日常茶飯事です。
つまり AZ 障害が発生してから復旧するまでの間に、生きてる AZ にいるいずれかのストレージノードが壊れることを考慮することに望ましさがあります。
レプリカ数=6、読み込み quorum=3、書き込み quorum = 4 という構成はこのようなクラウドの特性を考慮して決められています。
例えばよくあるレプリカ数3、quorum=2という構成や、レプリカ数=5、quorum=3という構成では、AZ + 1障害に耐えられることを保証できません。
書き込み可用性を若干妥協している点は読んでて少し気になりました。
AZ + 1障害に耐える書き込み可用性を提供することもおそらく可能で、例えばレプリカ数を9にすればマジョリティ方式で5、階層型 quorum なら最低4の書き込みで quorum を得ることができます。
ただ当然ネットワーク帯域とストレージ容量をより多く消費してしまう上に、書き込みはそもそもプライマリ DB ノードに障害が起きると結局しばらく停止せざるを得なさそうなので、そこまで頑張る必要もなさそうだなと思いました。
10GBに分割されたストレージ
前述の通り Aurora は AZ + 1障害に耐えられますが、AZ + 2の障害が発生するとデータベースを利用できなくなります。
これを防ぐには、AZ 障害を除いたノード故障が同時に発生しないようにする必要があります。
故障率を下げるのは難しいので、Aurora は修復までの時間を短くすることで多重障害に備えています。
その方法が、データを10GBのセグメントに分割し、ストレージノード群にばらまくというものです。
これにより壊れたレプリカのリペアを高速に行うことができ、結果故障が重複する確率を大きく下げることに成功しています。
10Gbps のネットワークを使えば、10GBセグメントの復旧は約10秒で行えます(ディスクアクセスが発生したらもう少し時間がかかるかもしれませんが、ストレージノードはローカル SSD にデータを保存しているらしいので、かなり速いんだろうなと勝手に思っています)。
10秒の間に AZ 障害に加え、同じセグメントのレプリカを持つノード2つに障害が発生する確率は非常に低いため、ほぼほぼデータロストなくデータベース機能を提供し続けることができます。
普通の MySQL なんかを運用してるとレプリカの復帰はかなり大仕事になりがちなので、すごくいい仕組みだと思いました。
redo ログのみを転送
Aurora は redo ログのみを転送することで、6レプリケーションに伴うネットワーク負担を軽減しています。
次の図は、MySQL with EBS をマルチ AZ 構成にしたときのデータの流れを示しています。
『Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases』の Figure 2 より
通常の MySQL はロギングからテーブルスペースへの書き込みなど、あらゆる書き込みが MySQL から実行されます。
そのため、EBS へのデータ転送量はかなり多くなります(iSCSI 的な仕組みを使ってネットワーク経由でデータを送受信するのだと思います)。
また、EBS 自体の冗長化機能に伴うネットワーク通信も発生します。
さらに冗長構成にすると、レプリカに対してもそれらのデータを送信する必要があります(MySQL は論理レプリケーションで binlog しか送信されないのでは、と思いましたが、Amazon RDS Multi-AZ 配備を見ると何やら物理レプリケーションしていると書いてあるので、binlog 以外も送っているのかもしれません)。
一方 Aurora は、ストレージノードに対して redo ログのみを、レプリカインスタンスに対して redo ログとメタデータを送信します。
『Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases』の Figure 3 より
redo ログの反映などはストレージノードがローカル SSD に対して非同期に行います。
そのため、ネットワーク上を流れるデータは redo ログとメタデータのみとなり、非常にネットワーク帯域を節約できます。
ただ MySQL with ローカルディスクを使って準同期レプリケーションを組めば論文で述べられていたようなネットワークコストはそもそも発生しないと思われます。
最新の MySQL だと準同期レプリケーションの ack 数を制御したりできるようなので、似たような冗長性とネットワーク帯域の節約を両立できそうです。
準同期レプリケーションにはそれはそれでディスアドバンテージがありそうですが、モノリシックなアーキテクチャでも理想的に設計すればこの点はそこそこいい感じになりそうだなと思いました。
感想
伝説の Amazon Aurora アーキテクチャがまとまってていい資料でした。
元の文章には他にも次のような内容が書かれています。
- 運用上の優位点
- 整合性を維持する方法
- クラッシュリカバリについて
- インフラ構成について
- ベンチマーク結果
MySQL との対比で説明されている部分も多く、データベースの基本的な仕組みに対する見識も深まるので、興味ある方は読んでみるとよさそうです。