Amazon Web Services ブログ

Amazon Aurora under the hood: クオーラムと障害

Anurag Guptaは幾つものデザインのヘルプを行った Amazon Auroraを含む AWS が提供するデータベースサービスの責任者です。このシリーズでは Anuragが Auroraを支える技術やデザインについて説明します。

Amazon Aurora ストレージは、ハイエンドなリレーショナルデータベースに求められる高いパフォーマンス、可用性、堅牢性要件を満たさなければならない分散システムです。これから 4回にわたって Amazon Aurora の設計に関する重要な要素を紹介します。この投稿はその第1回目です。

大規模なシステムにおいて必要な実世界の堅牢性、可用性、パフォーマンスのトレードオフを論じるパブリックドキュメントはあまり多くありません。このシリーズはトランザクショナルデータベースを設計する上での考慮点をベースにしていますが、ミュータブルな分散システムを設計する方に有用だと思います。

第1回目の投稿では、どのようにして Aurora ストレージでクォーラム採用するに至ったか、なぜ 3つのアベイラビリティゾーン(AZ)にわたる 6つのコピーを持つのかについてお話します。今回お話するいくつかは、SIGMOD paper にて論じたものです。

分散ストレージは素晴らしい考え方なのに、なぜうまく実現することが難しいのか
まず分散ストレージがなぜよい考え方なのかをお話しましょう。データベースソフトウェアとストレージを1つの箱に配置することで素早くデータベースを構築することは簡単です。この場合、その箱が障害に遭うことが問題となります。障害後にバックアップからリカバリするのに時間がかかります。バックアップされていない直近のデータが失われることを許容できるシステムはほとんどないでしょう。

データベースインスタンスからストレージを分離することで、障害に備えるということに加えて、柔軟性を高めることができます。お客様は、データベースを停止します。スケールアップやスケールダウンを行います。リードレプリカを加えたり、除去します。ストレージとデータベースとを疎結合にすることで、こういった操作が簡単になります。というのも、根幹となるストレージを新しい場所に再作成するのではなく、単にデタッチし、再度アタッチするだけでよいためです。データは重力を持ちますが、コンピュートは異なります。

もちろん、ストレージをコンピュートから分離させることだけでは、それぞれ障害に遭う可能性のある機器を増やしてしまうことになります。それゆえ、同期もしくは非同期のレプリケーションが利用されるのです。もし、障害が複数の機器にまたがるようなものでなければ、レプリケーションが堅牢性を高めます。

しかし、レプリケーションにも考慮が必要な点があります。同期レプリケーションでは、堅牢な書き込みを行うために、すべてのコピーが行われたことを認識されなければいけません。このアプローチでは、最も遅いディスク、ノード、もしくはネットワークに律速されることになります。非同期レプリケーションでは、レイテンシーが改善されますが、もしデータがレプリケートされる前に障害が発生した場合、データロスが起こりえます。どちらの選択肢も魅力的とは言えません。障害によって、レプリカのメンバーシップの変更が必要となります。このアプローチも面倒です。除去されるレプリカを再作成するのも高コストなので、このようなことを行うのは非常に保守的になります。この保守的な振る舞いは、レプリカを隔離するまで数分のダウンタイムが発生することを意味します。
クォーラムモデル
Aurora は代わりにクォーラムモデルを採用し、データコピーのサブセットに対して読み込み、書き込みを行います。V 個のコピーを抱えるクォーラムシステムは形式的に 2  つのルールに従うことになります。1 つ目は、読み込みクォーラム(Vr)、書き込みクォーラム(Vw)が、少なくとも1つのコピーを共通に持つ必要があります。

この方法では、もし 3つのコピーがある場合に、読み込みクォーラム、書き込みクォーラムが 2となり、それぞれがもう一方を確認することができます。このルールにより、データ項目が、2 つのトランザクションによって同時に読み込み、あるいは書き込みされないことが保証されます。また、読み取りクォーラムには、最新バージョンのデータ項目を含むサイトが少なくとも1つ含まれていることが保証されます。

2 つ目は、書き込みに使用されるクォーラムは、以前の書き込みクォーラムと重複があることを保証する必要があります。これは、Vw > V/2 という式を満たすことにより簡単に保証されます。このルールにより、同じデータ項目に対して、2つのトランザクションによる2つの書き込み操作が並列に発生しないことが保証されます。ここにいくつかのクォーラムモデルを示します。

V (コピーの数) Vw (書き込みクォーラム) Vr (読み込みクォーラム)
1 1 1
2 2 1
3 2 2
4 3 2
5 3 3
6 4 3
7 4 4

クォーラムシステムは、いくつか優れた特性があります。(例えば、リブートのために発生するような)一時的な障害やクォーラム内の1つのノードの遅延に対処するのと同じくらい簡単に、ノードの長期的な障害に対処できます。

The Aurora quorum
Aurora では、3 つの AZ にわたって、6 つのデータコピーを利用し、4 つの書き込みクォーラム、3 つの読み込みクォーラムを持っています。書き込みは 全 6つのデータコピーに対して発行され、6 つのコピーのうち4つから ACK が返ってきた時点で書き込みを完全に認めます。もし、そのうちの1つに遅延が発生していたとしても問題ありません。その他のノードが素早く返答し、遅れているノードは、可能な時に追いつきます。もし、ノードのうちの1つが少しの間、利用不能になった場合でも問題ありません。書き込み、読み込み能力が失われることはなく、そのノードも回復した際にリクエストを継続して受け付けます。そして、もしノードが永続的にダウンしたとしても、しばらく返答がないことを認識し、メンバーシップ変更プロトコルを利用して、新しいメンバーをクォーラムに追加します。

さて、なぜ 6 つのコピーなのでしょうか?前述の文言は、多くの商用の分散システムでもよく採用される 2/3 クォーラムの場合でも同様です。そのようなシステムでは、1つの障害を透過的に対処できます。こういったシステムでは、1つの障害に対応している間に、それと無関係なもう 1 つの障害が発生してしまう可能性があるということを極めてまれだと捉えています。

2/3 クォーラムの問題は、すべての障害が独立しているとは限らないということです。3 つの AZ にそれぞれ1つコピーをもつ 2/3 クォーラムを持っているとしましょう。AWS クラウドのような大規模分散システムでは、ノード、ディスク、ネットワークパス障害により、バックグラウンドでの小規模なノイズが常に発生しています。これ自体は全く問題ではありません。2/3 クォーラムでは、これらの障害に透過的に対処します。バックグラウンドでのノイズは、非常に小規模なので、同時に2つの障害が発生することは極めて稀です。

しかし、AWS リージョンを複数の AZ に分けた理由は、障害を分離するための領域を作るためです。仮に、AWS リージョン内の3つの AZ の内、1つがダウンしたとしましょう。屋根の崩落、火災、洪水、竜巻などのために、長時間ダウンするかもしれません。また、停電、不具合のあるソフトウェアのデプロイなどのために、短時間のダウンになるかもしれません。

こういった障害は、全てのクォーラムにおいて、3つのうちの 1つのコピーが失われる原因となります。既に障害対応をしている少数のクォーラムにとっては、二重障害となります。この時点で、1/3 のコピーのみ参照可能となり、このコピーがすべての書き込みを認識しているかを保証することはできません。この残った1つのコピーが、他の2つのコピーに対して、書き込みがなされた際に、スキップされたものだったという可能性もあります。このような場合、そのクォーラムは書き込み不可、読み込み不可、または復旧不可の状態となり、データベースボリュームが失われます。

6 つのコピーによるクォーラムモデルでは、書き込み可用性を失うことなく、AZ 障害を耐えることができ、AZ 障害とさらにもう1つの障害が重なったとしてもデータロストがありません。正当な読み込みクォーラムがある限り、データコピーを再構築し、完全に修復されたクォーラムを保持するかとができます。”AZ+1″ 障害モデルでは、3つの AZ と各 AZ ごとに 2つのコピーが必要な理由が明らかです。3/4 、または 3/5 クォーラムで運用することでも、”AZ+1″の目的を満たすことも可能ですが、リージョン内に 4つ、もしくは 5つの独立した AZ がある環境で運用した場合のみです。

6つのコピーは十分条件か?
6つのコピーは、必要条件ですが、十分条件でしょうか?この質問に対して、論理的に考えるには、平均故障間隔(MTTF)と平均復旧時間(MTTR)を通じて考える必要があります。ボリュームを修復する能力を失うには、読み込み可用性を失うことを必要とします。6 つのコピーによるクォーラムモデルでは、読み込み可用性を失うとは、6つのデータコピーのうち4つを失うことを意味します。これは、4つの独立した障害、2つの独立した障害、および1つのAZ障害、または2つのAZ障害のいずれかのことです。これらの可能性が最も高いのは、障害が発生したノードがあった後にAZ障害が発生し、最初に障害が発生したノードを修復している間に別のノードが停止することです。

それでも考えにくことですが、MTTF と MTTR が非常に悪い場合、そういったことが起こりえます。ある時点が過ぎると、MTTF や個別の障害が発生する可能性を改善するのが難しくなります。そのため、我々の最善策は、MTTR を小さくすることです。

Aurora では、データベースボリュームを 10 GB のチャンクに分けることによってこれを実現しています。各チャンクは、それぞれ 6つのコピーが利用している protection group に同期されます。大きいデータベースボリュームでは、数千のノードにわたって分散する可能性があります。10 GBでは、10 Gbit ネットワークを利用した場合に、1分以内にクォーラムの修復が完了します。一時的な問題を修復してしまうことを避けるため、検出時間とヒステリシスを考慮しても、MTTR はほんの数分です。その他の障害は、これと独立しているため、他の3つの障害、もしくは AZ 障害ともう1つの障害がこの時間枠で発生する可能性は低いと言えます。可能性はとても低いので、障害を挿入することさえ可能です。ストレージ層へのソフトウェアのデプロイメントは簡単です。単純にノードを停止し、ソフトウェアをインストールし、再起動するだけです。システムはこの障害に透過的に対応し、さらに多くのことを吸収できます。

このアプローチはホットスポット管理にも役立ちます。ホット・ディスクまたはノード上のセグメントを単に死んだとマークすることができ、ストレージ・フリート内の別のノードに自動的に修復されることを確認できます。

しかし、リビルド中に、もし実際に火災や洪水があり、数ヶ月間 AZ を失ったらどうなるでしょうか?この場合、6つのコピーのうち2つが失われてしまい、追加で、二重障害または AZ 障害があれば、データベースボリュームが失われます。考えすぎと言われるかもしれませんが、このようなことも考慮しています。壊滅的な災害が発生した後の、AZ を再建する MTTR です。

先ごろ、そのようなケースのためにデグレードモードへの切り替えを可能にするためのソフトウェアをデプロイしました。このモードでは、バックエンドで、AZ の長期的な喪失時に、3/4 書き込みクオーラムと 2/4 読み取りクオーラムに切り替えることができます。そして、AZ が再度、利用可能になった場合に、6つのコピーと 3AZ によるクオーラムに戻すことができます。このアプローチにより、残った AZ のうち 1 つに一時的な障害が発生しても復旧可能となり、書き込み可用性を失うことなく、さらにもう1つの障害に耐えることが可能です。

次回以降の投稿において、Aurora が前述のアプローチの欠点に対してどのように対処しているかを説明します。

  • パフォーマンス(クォーラムの参照は遅い)
  • コスト(6つのコピーを取得することはコスト増につながる)
  • 可用性(1つのボリュームを小さな複数のチャンクに分ける場合、メンバーシップの変更はコストの高い行為となる)

もしご質問などありまししたら、コメントもしくは aurora-pm@amazon.comにご連絡下さい。

次回: Amazon Aurora Under the Hood: クオーラムの読み取りと状態の遷移

翻訳は江川が担当しました。原文はこちら