Delta: チェーンレプリケーションを使用した高可用性、強く一貫したストレージ (2022)
要約
Metaが開発した新しいオブジェクトストレージサービス「Delta」について解説しています。Deltaは、ディザスタリカバリやブートストラップ戦略に不可欠なクリティカルなワークロード向けに設計されており、シンプルさと信頼性を最優先しています。チェーンレプリケーションを採用し、データの書き込みはチェーンの先頭から末尾へ順に行われ、読み込みは末尾から行われることで、強い一貫性と高可用性を実現しています。
全文翻訳
Delta: チェーンレプリケーションを使用した高可用性・強整合性ストレージ
長年にわたり、Metaはさまざまなユースケースやワークロード特性に対応する数多くのストレージサービスに投資してきました。その過程で、ストレージ分野のシステムを削減・統合することを目指してきました。同時に、クリティカルなパッケージワークロード専用のソリューションを持つことは、すべての人をより幸せにします。これは、私たちの災害復旧およびブートストラップ戦略に不可欠です。この認識と、Metaのビルドおよび配布アーティファクトにストレージを提供するというビジネス上の必要性が組み合わさり、新しいオブジェクトストレージサービスであるDeltaの構想が生まれました。
MetaのインフラストラクチャスタックにおけるDeltaの位置付け(下記参照)を考えてみましょう。これはスタックの最下層に位置し、インフラストラクチャの残りの部分の可用性とリカバリ可能性に必要な基本的なプリミティブを提供します。ブートストラップシステムの場合、ソリューションをより信頼性の高いものにする場合にのみ複雑さを導入すべきです。パフォーマンスと効率性については、最小限しか関心がありません。ブートストラップシステムに関するもう一つの考慮事項は、ブートストラップ自体です。エンジニアが少数のマシンにアクセスし、残りのインフラストラクチャを復元できるこのプロセスは、製品をユーザーが利用できる状態に戻すのに役立ちます。最後に、ブートストラップデータは、災害が発生した場合のリカバリのためにバックアップする必要があります。
[画像: MetaのインフラストラクチャスタックにおけるDeltaの位置付けを示す図]
この記事では、Deltaの目標、Deltaのアーキテクチャを governs する主要な概念、Deltaのプロダクションユースケース、リカバリプロバイダーとしての進化、および将来の作業項目について説明します。
Deltaとは何か?
Deltaは、シンプルで信頼性が高く、スケーラブルで、依存関係の少ないオブジェクトストレージシステムです。put、get、delete、list の4つの高レベル操作のみを備えています。Deltaは、シンプルさと信頼性を優先するために、レイテンシとストレージ効率をトレードオフします。水平スケーラブルであるため、Deltaは適切なフェイルオーバー戦略により、ソフトな依存関係に対して最小限の依存関係で済みます。
Deltaは以下のものではありません:
- 汎用ストレージシステム: Deltaのコア原則は、レジリエンスとデータ保護です。低依存性システムで使用されることを特に意図しています。
- ファイルシステム: Deltaはシンプルなオブジェクトストレージシステムとして機能します。Posixなどのファイルシステムセマンティクスを公開する意図はありません。
- ストレージ効率を最大化するように最適化されたシステム: レジリエンスを主要な原則とし、クリティカルシステムに焦点を当てているため、Deltaはストレージ効率、レイテンシ、またはスループットを最適化する意図はありません。
Deltaのアーキテクチャ
Deltaは、フェイルストップストレージサーバーのクラスターを調整するアプローチであるチェーンレプリケーションを本番環境で稼働させています。これは、強力な整合性保証を犠牲にすることなく、高スループットと高可用性を示す大規模ストレージサービスをサポートすることを目的としています。
Deltaがクライアントデータをレプリケートするためにチェーンレプリケーションをどのように活用するかを詳しく説明する前に、まずチェーンレプリケーションの基本を探ってみましょう。
チェーンレプリケーション
基本的に、チェーンレプリケーションはサーバーを線形にチェーン状に配置します。リンクリストのように、各チェーンはオブジェクトのレプリカを冗長に格納するホストのセットを含みます。
[画像: チェーンレプリケーションの概念図]
各チェーンは一連のサーバーを含みます。最初のサーバーをヘッド、最後のサーバーをテールと呼びます。下の図は4つのサーバーを持つチェーンの例を示しています。各書き込みリクエストはヘッドサーバーに送信されます。更新はチェーンを通じてヘッドサーバーからテールサーバーにパイプライン処理されます。すべてのサーバーが更新を永続化した後、テールは書き込みリクエストに応答します。読み取りリクエストはテールサーバーにのみ送信されます。クライアントがチェーンのテールから読み取れる内容は、チェーンに属するすべてのサーバーにレプリケートされており、強力な整合性が保証されます。
チェーンレプリケーション vs. クォーラムレプリケーション
チェーンレプリケーションが何を意味するかの概要を説明したので、他の広く使用されているレプリケーション戦略と比較してチェーンレプリケーションがどのように機能するかを探ってみましょう。
- ストレージ効率: チェーンレプリケーションは、明らかに最もストレージ効率の高いレプリケーション戦略を提供しません。チェーン内のすべてのホストにデータセット全体の冗長コピーを保存します。比較的に効率的なアプローチとしては、イレージャーコーディング技術を使用してデータフラグメントをインテリジェントにレプリケートすることが含まれます。
- 耐障害性: 最適なバケットレイアウトでは、チェーンレプリケーションはクォーラムベースのレプリケーションメカニズムと同等またはそれ以上の耐障害性を提供できます。なぜなら?
nノードのチェーンは、可用性を損なうことなく最大n – 2ノードまでの障害を許容できます。対照的に、クォーラムベースのレプリケーションシステムでは、書き込みを処理するために少なくともwホストが利用可能である必要があります。さらに、読み取りを処理するためにrホストが利用可能である必要があります。ここでwとrはそれぞれ書き込みクォーラムサイズと読み取りクォーラムサイズを表します。 - パフォーマンス: レプリケーション戦略(プライマリバックアップなど)では、すべてのバックアップサーバーが読み取りを処理できます。これにより、読み取りスループットが増加します。チェーンレプリケーションのネイティブな考え方では、チェーンのテールのみが読み取りを処理できます。(この部分は最適化されており、後でこの記事の「分割クエリ」セクションで詳細を共有します。)クォーラムベースのレプリケーションメカニズムと同様に、チェーンレプリケーションではすべての書き込みはプライマリ(チェーンのヘッド)に送信されます。しかし、チェーンレプリケーションでは、すべてのホストが更新を認識した後でのみ書き込みに応答されます。したがって、チェーンレプリケーションは、クォーラムベースのレプリケーションメカニズムと比較して、平均書き込みレイテンシが高くなります。
- クォーラムコンセンサス: クォーラムベースのシステムは、システム内のクォーラムを維持するために複雑なコンセンサスおよびリーダー選出メカニズムを必要とします。対照的に、チェーンレプリケーションベースのシステムにおけるクォーラムコンセンサスの範囲は、はるかに単純なチェーンホストマッピングに狭まります。例えば、チェーンヘッドは明示的なリーダー選出を必要とせずに、常に書き込み処理のリーダーとして機能します。
上記の相違点を考慮すると、チェーンレプリケーションは、マシン間でデータをレプリケートするための最もストレージ効率の高い方法を提供できないことは明らかです。さらに、すべてのリンクが更新を永続化した場合にのみ書き込みを成功と見なすため、クォーラムベースのシステムと比較して平均書き込みレイテンシが高くなります。しかし、それは非常にシンプルでありながら、同等の耐障害性と整合性保証を提供します。
Deltaバケットの解剖
チェーンレプリケーションの予備的な理解が得られたところで、Deltaがどのようにそれを利用して複数のサーバー間でデータをレプリケートするかについて説明しましょう。
上記の各Deltaバケットには、いくつかのチェーンが含まれています。各チェーンは通常、4つ以上のサーバーで構成されており、これは望ましいレプリケーションファクターに基づいて変動する可能性があります。各チェーン自体はレプリカセットとして機能し、データのスライスとトラフィックを処理します。これは、クライアントデータセットの論理的なシャードと考えることができます。特定のチェーン内のサーバーは、さまざまな障害ドメイン(電源、ネットワークなど)に分散されます。これにより、1つ以上の障害ドメインのサーバーが利用できなくなった場合でも、クライアントデータの耐久性と可用性が保証されます。私たちは、バケットのレイアウトに対する権威あるチェーンホストマッピングであるバケットコンフィグを維持しています。バケットにサーバーやチェーンを追加または削除すると、バケットコンフィグは適切に更新されます。
[画像: Deltaバケットの構造とチェーンの配置を示す図]
クライアントがDeltaバケット内のオブジェクトにアクセスすると、オブジェクト名のハッシュ関数が適切なチェーンを選択します。書き込みは常に適切なチェーンのヘッドに送信されます。データをローカルストレージに書き込み、チェーン内の次のホストに書き込みを転送します。書き込みは、チェーンの最後のホストがローカルメディアにデータを永続的に保存した後でのみ確認されます。読み取りは常に適切なチェーンのテールに送信されます。これにより、完全にレプリケートされたデータのみが表示および読み取り可能であることが保証され、それによって強力な整合性が保証されます。
Deltaは、バケットに新しいサーバーを追加し、サービスの可用性とスループットに影響を与えることなく、チェーンを新しく追加されたサーバーにインテリジェントに再分散することで、水平スケーラビリティをサポートします。例えば、最も多くのチェーンを持つサーバーが一部のチェーンを新しいサーバーに転送して負荷を再分散するという戦術があります。新しいバケットレイアウトは、望ましい障害ドメイン分散などを引き続き従い、チェーンの再分散とバケット容量の拡張中に採用されます。
Deltaにおける障害とリカバリモード
障害は、ホストのダウン、ネットワークのパーティション、計画メンテナンス活動、運用上のミス、またはその他の意図しないイベントから発生する可能性があります。チェーンレプリケーションの適切な実装では、サーバーはフェイルストップであると仮定します。つまり:
- 各サーバーは、誤った状態遷移を行うのではなく、障害に応答して停止します。
- サーバーの停止状態は、環境によって検出できます。
n個のチェーンがあり、各チェーンが1つ以上のホストで構成されているDeltaバケットを考えます。いずれかのホストが誤動作したり、ネットワークからパーティションされたりした場合、そのホストとチェーンを共有する他の兄弟ホスト(上流/下流)は、疑わしいホストを検出し、この動作を報告できます。
兄弟ホストは、単純なハートビートや、チェーンの上流/下流への確認/リクエスト送信の失敗を検出することで、誤動作ホストの誤動作を検出できます。複数のホストが特定のターゲットホストを疑う場合、そのホストはすべてのチェーンからキックアウトされ、修理のために送られます。バケットコンフィグは適切に更新されます。
ホストの異常な動作を検出する際には、いくつかの決定とトレードオフが発生します。
-
タイムアウト設定: 正しいタイムアウト設定に到達するために、いくつかのパフォーマンステストを実施しました。ホストを疑う前に、チェーン内の個々のリンク間のタイムアウトを慎重に評価する必要があります。サーバーは常に一時的なネットワーク問題に遭遇する可能性があるため、タイムアウトを短すぎに設定することはできません。タイムアウトを長すぎに設定することもできません。そうすると、操作レイテンシに悪影響を与える可能性があります。それだけでなく、クライアントも有効な応答を待っている間にタイムアウトする可能性があります。
-
疑わしいホストの投票設定: 特定のホストが異常であると投票するホストの数を、疑わしいホストがチェーンからキックアウトされる前に評価する必要があります。制限を1にすることはできません。なぜなら、チェーン内の2つのホストがお互いを異常と投票する可能性があるからです。これにより、両方のホストがチェーンから無効になります。制限を大きすぎにすることもできません。そうすると、異常なホストがフリートに長期間残り、サービスパフォーマンスに悪影響を与える可能性があります。各ホストは複数のチェーンに属しており、チェーン内の上流および下流ノードとの頻繁な接続が保証されています。その結果、疑いの投票制限を2に設定することは、私たちにとってうまく機能しました。さらに、障害ホストの修理フローを自動化しました。これにより、敏感なしきい値を設定し、より多くの誤検知を許容する柔軟性が得られます。
障害ホストが回復すると、キックアウトされる前にサービスしていたすべてのチェーンに追加できます。新しいホストは常にチェーンの末尾に追加されます。チェーンに戻された後、このホストは、チェーンの一部でなかった間にチェーンで発生したすべての更新と同期する必要があります。この再構築の間、ホストは上流ホストから新しい書き込みを受け入れることができます。しかし、上流ホストと完全に同期するまで、読み取りは上流に委任する必要があります。
このプロセスは、疑わしいホストを追加する場合と、Deltaバケットに新しい容量を導入する場合の両方に使用します。
[画像: チェーンレプリケーションにおける障害とリカバリのシナリオを示す図]
Deltaはどのように進化してきたか
分割クエリ
上記の記述から明らかなように、チェーンレプリケーションでの読み取り処理にはいくつかの大きな非効率性があります。
- テール、読み取りと書き込みの両方を処理する唯一のノードがホットスポットになる可能性があります。
- テールがすべての読み取りを処理することを考慮すると、チェーンのテールが読み取りスループットを制限します。
これらの制限を緩和するために、チェーンレプリケーションと分割クエリのアイデアにより、すべてのノードが読み取りを処理できるようにすることができます。
基本的なアイデアは? 各ノードが読み取りリクエストを処理します。しかし、クライアントの読み取りリクエストに応答する前に、重要なチェックを行います。要求されたオブジェクトのローカルコピーがクリーンであるか、またはチェーン内のすべてのサーバーによってコミットされているかを確認します。あるいは、オブジェクトがチェーン内のすべてのサーバーにレプリケートされていない「ダーティ」であると評価することもできます。サーバーは、クライアントに、チェーン内のすべてのサーバーによってコミットされたオブジェクトの最後のコミットバージョンを返すだけで済みます。これにより、クライアントはチェーンレプリケーションの強力な整合性保証を維持しながら、すべてのサーバーによってコミットされたオブジェクトバージョンのみを取得することが保証されます。テールノードは、特定のオブジェクトの最新のクリーンバージョンの権威として機能します。
[画像: 分割クエリの概念図]
上記で説明したように、チェーン内の各非テールリンクは、クライアントへの応答の前にチェーンテールへの追加のネットワークコールを行います。これは、オブジェクトのクリーンバージョンを取得するために行われます。クライアントの読み取りに応答する前に。この追加のネットワークコールは大きな価値を提供します。なぜなら? それは、読み取りスループットとチェーン帯域幅をチェーン長に線形にスケールさせるのに役立ちます。さらに、これらのオブジェクトバージョンチェックコールは、実際のクライアント読み取りを処理するよりも安価です。したがって、クライアントのレイテンシに大きな影響を与えることはありません。
自動修復
ハードウェア障害やネットワークパーティションはまれに見えるかもしれませんが、大規模クラスターではかなり頻繁に発生します。そのため、頻繁な手動介入を避けるために、障害検出、ホスト修復、およびリカバリは自動化されるべきです。
Deltaのフリート管理を自動化する制御プレーンサービス(CPS)を構築しました。CPSの各インスタンスは、Deltaバケットのリストを監視するように構成されます。その主な機能は、欠落しているリンクを持つチェーンを修復することです。
[画像: 制御プレーンサービス(CPS)によるチェーン修復のワークフローを示す図]
チェーンを修復する際、CPSはいくつかの技術を適用して最大の効率を達成します。
- バケットを修復する際、CPSはバケットレイアウト内のすべてのチェーンの障害ドメイン分散を維持する必要があります。これにより、バケットホストがすべての障害ドメインに均等に分散されることが保証されます。
- CPSは、すべてのサーバーに均一なチェーン分布を確保する必要があります。これにより、一部のサーバーが他のホストと比較して大幅に多くのチェーンをホストすることによって過負荷になるのを回避します。
- チェーンにリンクが欠落している場合、CPSは新しいホストよりも元のホストでチェーンを修復することを優先します。なぜなら? 新しいホストにすべてのチェーンコンテンツを同期することは、元のホストが修理から戻ったときに部分的なチェーンコンテンツを同期することと比較して、計算集約的になるからです。
- ホストをチェーンに有効にする前に、CPSは詳細な健全性チェックを実行して、正常なホストがバケットに追加されることを保証します。
- バケット内のサーバーを管理することに加えて、CPSは正常なスタンバイサーバーのプールも維持します。チェーンのホストの50%以上が欠落した場合、CPSはチェーンに新しいスタンバイホストを追加します。これにより、深刻なホスト不足のチェーンがバケットの可用性を危険にさらすことがなくなります。これを行う間、CPSは上記のすべての原則を最善努力で適用しようとします。
グローバルレプリケーション
Deltaの元の実装では、Deltaクライアントがデータ安全性の考慮から複数のリージョンにブロブを保存したい場合、各リージョンにリクエストを送信していました。これは明らかにユーザーの観点からは理想的ではありません。Deltaのユーザーは、冗長性とジオディストリビューションのレベルを制御できる一方で、オブジェクトの場所を追跡するビジネスに従事すべきではありません。クライアントアプリは、ストアにオブジェクトを1回だけ配置し、基盤となるサービスファブリックが変更をすべてに伝播することを期待できるはずです。取得についても同様です。定常状態では、クライアントはリクエストを送信してオブジェクトを取得し、サービスがその時点で利用可能な最も最適なソースから取得することを期待できます。
サービスが進化するにつれて、クライアントリージョンへのグローバルレプリケーションを導入しました。これはハイブリッド方式で行われます。少数のリージョンへのブロブの同期レプリケーションと、残りのリージョンへの非同期レプリケーションの組み合わせです。少数のリージョンへの同期レプリケーションは、クライアントのレイテンシを削減し、他のリージョンが最終的に整合性の取れた方法でブロブを取得することを保証します。特定のリージョンがネットワークパーティションまたはアウトエージを経験すると想像してください。システムは、ジオレプリケーションに参加するそのリージョンを除外するインテリジェントな処理を行います。その後、そのリージョンは、欠落したブロブで非同期的にバックフィルされる可能性があります。
[画像: グローバルレプリケーションのアーキテクチャを示す図]
Deltaは災害復旧をどのように処理するか
Deltaの主要な原則の1つは、可能な限り依存関係を少なくすることです。最小限の依存関係を持つことに加えて、信頼性の高い災害復旧ストーリーにも投資してきました。
現在、クライアントブロブをコールドストレージに継続的にバックアップするために、アーカイブサービスと統合しています。さらに、これらのアーカイブサービスからオブジェクトを継続的に復元する機能を開発しました。アーカイブサービスとの標準的な統合は、深刻な劣化環境で信頼性の高いリカバリ可能性保証を提供します。災害復旧保証により、当社のサービスと統合しているパートナーチームがいくつかあります。
[画像: Deltaの災害復旧機能を示す図]
Deltaの今後
今後、Meta内のコアインフラストラクチャサービス向けの集中型バックアップおよび復元サービスを、Deltaストレージに基づいて構築する予定です。信頼性の高いステートフルサービスは、内部状態のスナップショット(バックアップ)を生成し、スナップショットから内部状態を再水和(復元)できる必要があります。私たちの究極の目標は、すべてのアーカイブサービスへのゲートウェイとして位置付けられ、クライアントに集中型のバックアップ提供を行うことです。さらに、Deltaの災害準備および復旧ストーリーの信頼性を向上させるために、大幅な投資を計画しています。これにより、ユーザーに対して信頼性が高く堅牢なリカバリプロバイダーとして機能できるようになります。