Category: MySQL compatible*


Amazon Aurora Under the Hood: クオーラムメンバーシップ

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

この記事は、Amazon Auroraがどのようにクオーラムを使用するのかをお話する4回シリーズの最後です。最初の記事では、障害が発生した場合に必要なクォーラムのメリットとメンバの最小数について説明しました。2回目の記事では、読み書きを行う際に利用するネットワーク帯域の増加を避けるために、ロギング、キャッシュの状態、および非破壊的な書き込みを使用する方法について説明しました。3回目の記事では、より高度なクォーラムモデルを使用して複製コストを削減する方法について説明しました。クォーラムに関するこの最後の記事では、クォーラムメンバーシップの変更を管理する際にAmazon Auroraが問題を回避する方法について説明します。

クオーラムメンバーシップの変更を管理するテクニック
マシンは故障します。クオーラムメンバの1つが破損すると、ノードを交換することによってクオーラムを修復する必要があります。これは複雑な決定になります。 クォーラムの他のメンバーは、障害のあるメンバに一時的なレイテンシーの増加が発生したか、再起動のための短期間の可用性低下が発生したか、または永久にダウンしたかどうかを判断できません。 ネットワークパーティションにより、複数のメンバーグループが同時にお互いに隔離を実行出来ます。

ノードごとに大量の永続状態を管理している場合、クォーラムを修復するための状態の再複製には長い時間がかかります。 そのような場合、障害のあるメンバーが復帰できる場合に備えて修復を開始することについて慎重に行う必要があります。 多くのノードで状態をセグメント化することで、修復時間を最適化することができます。 しかし、これは失敗の可能性を高めます。

Auroraでは、データベースボリュームを10GBのチャンクに分割し、3つのアベイラビリティゾーン(AZ)に分散した6つのコピーを使用します。 現在の最大データベースサイズが64TBなので、プロテクショングループは6,400個、セグメント数は38,400個です。 このスケールでは破損は一般的に発生する可能性があります。 メンバーシップの変更を管理する一般的な方法は、一定期間リースを使用し、各リースでメンバーシップを確保するためにPaxosなどのコンセンサスプロトコルを使用することです。 しかし、Paxosは処理負荷のかかるプロトコルであり、最適化されたバージョンでは多数の障害が発生します。

障害を管理するためにクオーラムセットを利用する
Auroraはメンバーシップの変更を管理するために、ロギング、ロールバック、コミットなどのクォーラムセットとデータベース技術を使用します。 A、B、C、D、E、Fの6つのセグメントを持つプロテクショングループを考えてみましょう。この場合、書き込みクォーラムはこの6組のうち4つのメンバーであり、読み取りクォーラムは3つのメンバーです。 前回の記事でご紹介したように、Auroraのクオーラムはこれよりも複雑ですが、今は単純に考えてみることにします。

Auroraの読み書きはそれぞれ、メンバーシップエポックを使用します。これは、メンバーシップの変更ごとに単調に増加する値です。 現在のメンバーシップエポックよりも古いエポックにある読み取りと書き込みは拒否されます。そのような場合、クオーラムメンバーシップの状態をリフレッシュする必要があります。 これは、概念的には、REDOログ内のlog sequence numbers(LSN)の概念に似ています。 エポックナンバーおよび関連する変更記録は、メンバーシップに順序付けられたシーケンスを提供します。 メンバーシップエポックを変更するには、データ書き込みと同様に書き込みクォーラムを満たす必要があります。 現在のメンバーシップの読み込みには、データの読み込みと同様のリードクオーラムが必要です。

ABCDEFのプロテクショングループの話を続けましょう。セグメントFが破損した可能性があるとし、新しいセグメントGを導入する必要があると考えてください。一時的な障害に遭遇する可能性があり、迅速に復帰する可能性があります。またはリクエストを処理しているかもしれませんが、なんらかの理由で検出出来ない可能性があります。また、Fが復活したかどうかを確認するのを待ちたくはありません。クオーラムが損なわれて2回目の障害が発生する可能性が増加だけです。

これを解決するためにクォーラムセットを使用します。 私たちはABCDEFからABCDEGに直接メンバーシップの変更をすることはありません。代わりに、メンバーシップのエポックを増やし、クォーラムセットをABCDEFとABCDEGに移動します。書き込みはABCDEFの6つのコピーのうち4つから正常に行われなければならず、またABCDEGの6つのコピーのうち4つからackが返る必要があります。 ABCDEのどの4つのメンバーは両方とも書き込みクォーラムを満たしています。 読み取り/修復クォーラムは同じように動作し、ABCDEFからの3つのackとABCDEGから3つのackが必要です。ABCDEからの3つのいずれかが両方を満たします。

データがノードG上に完全に移動され、Fを取り除くと決定した場合、メンバーシップエポックの変更を行い、クォーラムセットをABCDEGに変更します。エポックの使用は、コミットLSNがREDO処理のために行うのと同様に、これをアトミックに行います。このエポックの変更は、現在の書き込みクォーラムが満たされている必要があり、他のアップデートと同様に、ABCDEFの6つのうち4つと、ABCDEGの6つのうちの4つからのackが必要です。Gが利用可能になり前に再びノードFが利用可能になると、変更を元に戻しメンバーシップエポックの変更をABCDEFに戻します。完全に健全なクオーラムに戻るまで、いかなる状態やセグメントも破棄しません。

このクォーラムへの読み書きは、メンバーシップの変更中に、変更前または変更後と同じように行われることに注意してください。 クォーラムメンバーシップへの変更は、読み取りまたは書き込みをブロックしません。失効したメンバーシップ情報を持つ呼び出し元は、状態をリフレッシュして正しいクォーラムセットに要求を再発行します。また、クオーラムメンバーシップの変更は、読み取り操作と書き込み操作の両方に対して非ブロッキングです。

もちろん、Fの代わりにGへデータを移動しクオーラムを修復している間にABCDEGのいずれかが破損する可能性もあります。多くのメンバーシップ変更プロトコルはメンバーシップの変更中に障害を柔軟に処理しません。クォーラムセットとエポックでは、簡単です。Eも破損してHに置き換えられる場合を考えてみましょう。ABCDEFとABCDEGとABCDFHとABCDGHのクオーラムに移動するだけです。単一障害と同様に、ABCDへの書き込みはこれらのすべてを満たします。メンバーシップの変更は、読み取りと書き込みの失敗と同じ範囲になります。

まとめ
クォーラムセットをメンバーシップの変更に使用することにより、Auroraは小さなセグメントを使用することができます。これにより、Mean Time To Repair(MTTR)および複数の障害に対する可能性を削減することで、耐久性が向上します。また、お客様のコストを削減します。Auroraのボリュームは必要に応じて自動的に増加し、小さなセグメントでは少しずつ増加します。クォーラムセットを使用することで、メンバーシップの変更が行われている間も読み取りと書き込みが継続できるようになります。

メンバーシップの決定を元に戻すことができれば、積極的にクオーラムを変更することができます。障害のあったメンバーが返ってくると、いつでも変更を元に戻すことができます。いくつかの他のシステムでは、リースが期限切れとなり、クオーラムメンバシップを再確立する必要があるため、定期的な停止が発生します。Auroraは、リースが期限切れになるまでメンバーシップの変更操作を延期するという耐久性の犠牲を払わず、クオーラムメンバシップが確立されている間に読み込み、書き込み、またはコミットを遅らせるというパフォーマンス上のペナルティも発生しません。

Auroraは、さまざまな分野で進歩を遂げています。データベースと分散システムを統合するアプローチは、これらの多くの中核を成しています。クォーラムをどのように使用するかについてのこの連載をご覧いただき、ご自身のアプリケーションやシステムを設計する方法について考えるときに役立てて頂けると思います。今回使用した手法は広く適用可能ですが、スタックの多くの要素にに対して適用する必要があります。

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

翻訳は星野が担当しました (原文はこちら)

Amazon Aurora Under the Hood: クオーラムセットを使ったコスト削減

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

このポストはAmazon Auroraが利用しているクオーラムの仕組みについての4回の連載の3本目です。このポストを皆様がご自身で分散システムをデザインする際に活用頂けると幸いです。今回は、クオーラムシステムでどのようにコストを管理するかについてご説明します。

私たちが取り組んでいる基本的な問題は、Auroraが6つのアベイラビリティゾーン(AZ)に分散した6つのクォーラムを使用し、6つのコピーのうち4つを使用して書き込みを行い、読み取り/修復のために6つのコピーのうち3つを使用することです。 このシリーズの最初の記事では、なぜ6つが最小限必要なコピー数であるのかをご説明しました。 2番目の記事では、書き込みと読み取りの両方でクォーラムのパフォーマンスの低下を避ける方法について説明しました。 しかしそれはまだ多くのデータのコピーであり、コストが多くかかります。 Amazon Auroraのストレージが低価格なのは、何か特別なことをしているのではと考えさせるきっかけになるかもしれません。

私たちが何をしているか理解するためには、クオーラムの基本的な定義に戻る必要があります。 一般的に、クオーラムについて書き込み用のセットが大部分の要素を表し、読み書きで必要なセットが重複していいると表現します。 これは正しいのですが、単純化された説明です。 基本的な要件は、読み取りと書き込みのセットがすべてのクオーラムメンバーシップセットのサブセットであることです。正当な書き込みサブセットの場合、少なくとも1つのメンバーも正当な読み取りサブセット内に含まれ、各書き込みサブセットは以前の書き込みサブセットと重複します。 同じように思えますが、そうではありません。

違いは、クオーラムメンバーが互いに同じであるという要件はないということです。 異なるレイテンシ、コスト、または耐久性の特性を持つクォーラムサブセットをうまく組み合わせてクォーラムセットを構築できます。 ブール論理のルールを使用して、完全なクオーラムのクオーラムメンバシップ要件を満たすために、各サブセットにわたってより高度な読み書きルールを作成することができます。 それでは、コストを削減するためにAuroraではこれらをどのように行っているのかを見てみましょう。

Mixing full and tail segments of data
Auroraでは、データベースボリュームは10GBのデータセグメントで構成されています。 これらのセグメントはプロテクショングループとして複製され、6つのコピーが3つのAZに分散しています。 しかし、6つのコピーはすべて同じではありません。 コピーの半分はフルセグメントで、ボリュームの10GB部分のデータページとログレコードの両方を含んでいます。 残りの半分は、ログレコードのみを含むテールセグメントです。 各AZには、1つのフルセグメントと1つのテールセグメントが含まれています。

ほとんどのデータベースには、REDOログストレージよりもはるかに多くのデータブロックストレージがあります。 フルセグメントとテールセグメントを組み合わせて使用すると、Auroraの物理ストレージに必要な要件がデータベースの6倍から、3倍より少し多い程度になります。 “AZ+1″の障害に耐えるように設計されたシステムでは、これは最小限のレプリケーションファクターです。

フルセグメントとテールセグメントの組み合わせを使用すると、読取りセットと書込みセットをどのように構築する必要があるかが変わります。 ブール論理のルールを使用して、サブセット間の重複を保証し、メンバーの複雑な分布に対しても正確にそれを行うことができます。 Auroraでは、書き込みクオーラムは6つのセグメントのうち任意の4つ、または3つのフルセグメントのうち3つです。 読み込みクォーラムは、6つのセグメントのうち任意の3つと3つのフルセグメントから1つです。 このことから、クォーラム内のすべてのセグメントに重複があり、フルセグメント上に重複があることがわかります。 これにより、以前に行った6つのセグメントのうち4つにログレコードを書き込むことができます。 これらのうち少なくとも1つはフルセグメントであり、データページを生成します。 前回の記事で説明した最適化を使用して、フルセグメントからデータを読み込み、クオーラムの読み取りを回避しすることで必要なデータを持っているものから読み込むことが出来ます。

破損したセグメントを再構築し、問題のあるクォーラムを修復する方法として読み込みクォーラムを使用します。 また、データベースのマスターノードを再起動する必要がある場合は、ローカルの状態を再構築するためにも使用します。 テールセグメントの1つが破損した場合は簡単です。 単純なクオーラムモデルと同じように他の3つのコピーのいずれかから修復します。

フルセグメントの1つが破損した場合、もう少し複雑です。 破損したものは、書き込みの一部として書き込んだもののコピーであった可能性があります。 しかしその場合、最新の書き込みを見ていなくても、別の完全なセグメントがあります。 また、フルセグメントを最新なものに再構築できる十分なREDOログレコードのコピーがあります。 また、クォーラムのセグメント間をゴシップを利用して、不足している書き込みをすばやく埋めることができます。ここれにより、書き込みパスにパフォーマンスの負担をかけることなく、フルセグメントを再構築する必要がなくなります。

異なるメンバーのクォーラムセットによるコストの管理
異なるメンバーのクォーラムセットを使用すると、コストを抑えることができます。 利用可能な多くのオプションがあります。 低レイテンシのローカルディスクと耐久性/可用性のためのリモートディスクを組み合わせたクォーラムがあるかもしれません。 パフォーマンスとスループットのためにSSDを組み合わせたクォーラムと、低コストのレプリカで耐久性を向上させるHDDがあるかもしれません。 災害復旧を改善するためにAWSリージョン全体でデータを複製するクォーラムがあるかもしれません。適切な組み合わせを考えるために考慮することが沢山ありますが、その結果の利益は重要です。 Auroraの場合、先に説明したクォーラムセットモデルでは、低コストのストレージ価格を実現しながら、高い耐久性、可用性、パフォーマンスを提供します。

これまで、このシリーズでは、クォーラムのサイズを決める方法、読み取りと書き込みの増幅のペナルティを回避する方法、そしてこの記事でコストを制御する方法について説明しました。 次回の記事では、障害に直面した大規模分散システムでの管理コストの少ないクオーラムメンバーシップの管理方法について説明します。

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

次回: Amazon Aurora Under the Hood: クオーラムメンバーシップ

翻訳は星野が担当しました (原文はこちら)

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

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

前回の投稿では、クォーラムモデルの利点をお話しました。レイテンシーの異常値や短期間のダウンタイム、ディスクとノードの長期的な喪失に直面して、このようなシステムがいかに耐久性があるかについて説明しました。この投稿は、1つの疑問を提起します – もし、クオーラムがとても素晴らしいのであれば、なぜ皆使わないのでしょうか?

クォーラムシステムにおける読み取りの性能劣化
1つの問題は、クォーラムシステムでは読み取りが遅くなることです。クォーラムモデルでは、読み込みクォーラム、書き込みクォーラムともに、少なくとも1つのメンバーが必要です。 Amazon Aurora のような6つのメンバーを持つクォーラムシステムでは、書き込みクォーラムの 4 つメンバーを持ちながら、3つのデータのコピーを読み込む必要があります。これは不運です。データベースのページを読み取る場合、通常、バッファキャッシュにヒットしなかったことを意味し、次の処理に進む前に、I/O 処理を待って、SQL 文がブロックされます。3つのデータのコピーを読むには、およそ5回アクセスすることで、異常値を含むレイテンシーや一時的に発生する可用性の問題に対処するのが良いでしょう。そのようにすることは、ネットワークに大きな負荷をかけることになります。データベースページは、かなり大きく、読み取りによる増幅は容易に想像できます。クォーラムシステムの読み取りパフォーマンスは、従来のレプリケーションシステムと十分に比較されているとは言えません。従来のレプリケーションシステムでは、データがすべてのコピーに書き込まれますが、読み取りは、そのうちのどれか1つへアクセスします。

しかしながら、Aurora は、書き込み中、クォーラムによる増幅を避けています。Aurora では、6つのコピーに対して書き込みを行いますが、ログレコードしか書き込みません。データページの全領域を書き込むわけではありません。データページは、以前のバージョンのデータページと送られてくるログを元にストレージノードで組み立てられます。また、非同期に書き込むことができます。これらは読み取りには対応できません。

読み込みクォーラムのオーバーヘッドを避ける方法
読み込みクォーラムのオーバーヘッドは、クォーラムシステムにとって明らかに不利な点です。どのように避けることができるでしょうか?鍵となるポイントは、状態(state)を使うことです。

ノードをスケールさせるに伴い、一貫した状態を管理し、調整するのが難しいため、分散システムにおいて、状態という単語はしばしばよくないワードとして考えられ、不具合を引き起こします。もちろん、データベースシステムの全目的は状態を管理し、原子性、一貫性、独立性、永続性(ACID)を提供することです。Aurora は、これら二つの技術領域が交わる点に位置します。我々のイノベーションの大部分は、1つの領域のコンセプトを適用し、もう1つのドメインの進化を推し進めることから生まれています。

もっとも、通信なしに分散されたそれぞれの状態を一致させることは困難ですが、一致、調整、またはロックの必要性を避けるために利用できる一貫性のローカル領域があります。ここで紹介できる例としては、リードビューがあげられます。多くのデータベースシステムでも同様のコンセプトを持っていますが、ここでは MySQL にフォーカスします。

全てのリレーショナルデータベースと同様に、MySQL は ACID をサポートします。リードビューは論理的な時点を確立します。SQL 文は、その時点より前にコミットされた全ての変更を参照可能となり、まだコミットされていない変更は参照できないようにならなければいけません。MySQL では、直近のコミットのログシーケンス番号(LSN)を確立することで、これを実現しています。このアプローチにより、既にコミットされているすべての変更が参照可能となることが保証され、アクティブなトランザクションの一覧を利用することで、参照されてはならない変更の一覧を作成します。特定のリードビューに対するSQL 文がデーターページをチェックする際、その SQL 文がリードビューを確立した時点でアクティブだったトランザクションに対するいかなる変更も見えなくする必要があります。たとえ、これらの変更が現在コミットされたものであったとしてもこれは同様であり、リードポイントコミット LSN の後に開始された全てのトランザクションについても同様です。トランザクションがリードビューを確立した際に、一貫性のある時点に適切に戻すことができるのであれば、システムで実行されるいかなる変更からも、そのトランザクションから分離できます。

読み込みクォーラムにおいて、これをどう実現すれば良いでしょうか?全てです。データベースは、ストレージノードに対して継続的に書き込みを行います。ACK を受け取るたびに、データベースは各変更が堅牢なものであるとマークします。それ以前の全ての変更がそれぞれ堅牢であると登録されると、ボリュームポイントが堅牢であると更新されます。参照リクエストが来ると、そのリクエストは、データベースが参照しなければならない リードポイントコミット LSN を持ちます。 そのリクエストは、データベースによって、リードポイントコミットLSN を処理可能なことが分かっているストレージノードへと単に転送されます。

このアプローチでは、簿記のように状態管理を行うことによって、クォーラムの読み取りを回避します。その代わり、必要とするデータバージョンを把握しているノードから読み取りを行います。このアプローチにより、ネットワーク、ストレージノード、データベースノードで行われる通信を大幅に抑えられます。

レイテンシーを避ける方法
しかしながら、読み込みクォーラムを避けることによって、単一のストレージノードのレイテンシーに左右されることになります。これについては、ストレージノードに対する読み取りリクエストのレスポンスタイムをトラックすることにより対応してます。通常、読み取りリクエストは最もレイテンシーの低いノードに対して行われます。レイテンシーの情報を最新に保つため、時折、その他のノードに対してもクエリされます。

これは、1つのデータベースノードに対しては非常に分かりやすい作業です。なぜなら、全ての書き込みを認識し、全ての読み込みを調整することができるからです。リードレプリカのことを検討する場合、より複雑です。 Aurora では、リードレプリカは同じストレージボリュームを共有します。同時にマスターデータベースノードから、非同期にマスターの redo ログストリームを受け取り、キャッシュ上のデータページを更新します。このアプローチは、コストの観点で最も安いというだけではなく、データロストや同期レプリケーションによる書き込みレイテンシーなしに、レプリカのマスターノードへの昇格を可能にします。マスターノードへの ACK によりコミットされたとマークされた変更は、たとえレプリカにまだ伝播していなかったとしても、すべて堅牢です。これらのレプリカノードは、それぞれで読み込みを行い、書き込みとその ACK を見ることはできず、それにより何を読み込むべきか把握することはできません。

そのため、redo レコードがマスターからレプリカへ送られる際に、概念的にリードビューと同等のものが送られます。このビューにより、コミットLSNとLSNが堅牢であると示すセグメントの情報が更新されます。通常、コミットLSN を約 10ミリ秒ごとに更新することができます。それにより、レプリカをマスターノードとの差分を最小限に保ちます。

破壊的な書き込みの回避
このアプローチの鍵は、破壊的な書き込みの回避です。リードレプリカとマスター間の通信を調整しなければいけない理由の大部分は、読み取るデータが確実に表示されるようにすることです。以前のページイメージに戻すことができる限りは、リードビューにより、その調整負荷は大幅に減少されます。Aurora では、データページを別の場所に書き込みます。古いバージョンは、バックアップされ、すべてのリーダーがリードポイントをそのバージョン以上に更新した際に、ガベージ・コレクションされます。このアプローチにより、マスターノードより数ミリ秒遅れているレプリカノードでも一貫したビューを持つことができます。

トランザクションをロールバックすることがあったとしても、リレーショナルデータベースは、その根底において、常に更新される redo ログです。データベースを構成するデータページは、実のところ、アプリケーションの redo ログを一時的にキャッシュして具現化したものに過ぎません。多くのデータベースが破壊的にデータページを書き込むという事実は、実際、リレーショナルデータベースが最初に作成された際の高コストなディスクに基づく歴史的な好奇心です。

Aurora では、上記で説明したアプローチを用いるため、読み込みクォーラムを利用しません。その代わり、修復クォーラムを利用します。読み込みクォーラムにクエリする必要があるのは、書き込みマスターデータベースノードにおいてキャッシュの状態を失う時だけです。もし、マスターインスタンスを再起動、もしくはレプリカをマスターに昇格させなければいけない場合、ローカルの状態を再構築するため、少なくとも1度、読み込みクォーラムにクエリする必要があります。いずれにしても、どのようなトランザクションがコミットされているか把握するためにそうしなければならないことは明らかでしょう。これについては、いつか別のブログでお話しすることになるかもしれません。データベースのクラッシュが、読み取りに比べて発生頻度が少ないことを考えると、このトレードオフをとる価値があります。

まとめ
この投稿と前回の投稿で、可用性を提供するためにどのようにクォーラムを使用するか、どのように従来の読み込みクォーラムのオーバーヘッドを回避するかについて確認しました。次回の投稿では、クォーラムシステムをコストの観点でどのように利用しやすくするかについてお話します。もしご質問などありまししたら、コメントもしくは aurora-pm@amazon.comにご連絡下さい。

次回: Amazon Aurora Under the Hood: クオーラムセットを使ったコスト削減

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

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: クオーラムの読み取りと状態の遷移

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