Orleans でのクラスター管理

Orleans は、組み込みのメンバーシップ プロトコルを使ってクラスター管理を提供します。これは、サイロ メンバーシップと呼ばれることもあります。 このプロトコルの目的は、すべてのサイロ (Orleans サーバー) が現在稼働しているサイロのセットに合意し、障害が発生したサイロを検出し、新しいサイロのクラスターへの参加を許可できるようにすることです。

このプロトコルは、外部サービスに依存して IMembershipTable の抽象化を提供します。 IMembershipTable はフラットな NoSQL に似た永続テーブルであり、2 つの目的に使われます。 第一に、サイロの相互検出および Orleans クライアントによるサイロの検出のためのランデブー ポイントとして使われます。 第二に、現在のメンバーシップ ビュー (ライブ サイロのリスト) を格納するために使われ、メンバーシップ ビューでの合意を調整するのに役立ちます。 現在、IMembershipTable には、Azure Table Storage、SQL Server、Apache ZooKeeperConsul IOAWS DynamoDB、および開発用のメモリ内エミュレーションのそれぞれに基づく 6 つの実装があります。

IMembershipTable に加えて、各サイロは、障害が発生したサイロを検出し、稼働しているサイロのセットに合意する、完全に分散されたピアツーピア メンバーシップ プロトコルに参加します。 最初に、Orleans のメンバーシップ プロトコルの内部実装について説明した後、IMembershipTable の実装について説明します。

基本メンバーシップ プロトコル

  1. 起動時に、すべてのサイロは、IMembershipTable の実装を使って、既知の共有テーブルにそれ自体のエントリを追加します。 サイロ ID (ip:port:epoch) とサービス デプロイ ID の組み合わせが、テーブルでの一意キーとして使われます。 エポックはこのサイロが起動した瞬間の時刻であり、そのため ip:port:epoch は特定の Orleans のデプロイにおいて一意であることが保証されます。

  2. サイロは、アプリケーションの ping ("稼働確認" の heartbeats) を介して相互に直接監視します。 ping は、サイロの通信と同じ TCP ソケット経由で、サイロ間の直接メッセージとして送信されます。 それにより、ping は実際のネットワークの問題やサーバーの正常性と完全に関連します。 すべてのサイロは、他のサイロの構成可能なセットに ping を実行します。 サイロは、他のサイロの ID に対してコンシステント ハッシュを計算し、すべての ID の仮想リングを形成し、リング上で X 個の後継サイロを選択することによって、ping する対象を選択します (これは、コンシステント ハッシュ法と呼ばれるよく知られた分散手法であり、Chord DHT などの多くの分散ハッシュ テーブルで広く使われています)。

  3. サイロ S は、監視対象サーバー P から Y 個の ping 応答を受け取らなかった場合、タイムスタンプ付きの疑いを IMembershipTable の P の行に書き込むことによって疑いを表明します。

  4. P の疑いが K 秒以内に Z 個を超えた場合、S は P が稼働していないことを P の行に書き込み、メンバーシップ テーブルの再読み取り要求をすべてのサイロにブロードキャストします (いずれにしても、これは定期的に行われます)。

  5. さらに詳しく説明すると次のようになります。

    1. 疑いは、IMembershipTable の P に対応する行の特別な列に書き込まれます。S は、P を疑うと、"at time TTT S suspected P" (時刻 TTT に S は P を疑った) と書き込みます。

    2. 1 つの疑いでは、P を非稼働と宣言するのに十分ではありません。 P を非稼働と宣言するには、構成可能な時間枠 T (通常は 3 分) の間に、異なるサイロからの Z 個の疑いが必要です。 疑いは、IMembershipTable によって提供されるオプティミスティック同時実行制御を使って書き込まれます。

    3. 疑っているサイロ S は、P の行を読み取ります。

    4. S が最後に疑ったサイロである場合 (T の期間内に、既に Z-1 個のサイロが疑って、疑い列に書き込んでいる)、S は P を非稼働と宣言することを決定します。 この場合、S は、疑っているサイロのリストに自分自身を追加し、P の状態列に P が非稼働であることも書き込みます。

    5. そうではなく、S が最後に疑ったサイロでない場合、S は疑っているサイロの列に自分自身を追加するだけです。

    6. どちらの場合も、ライトバックでは読み取られたバージョン番号または ETag が使われるため、この行の更新はシリアル化されます。 バージョンまたは ETag の不一致により書き込みが失敗した場合、S は再試行します (P が既に非稼働とマークされていない限り、再度読み取って、書き込みを試みます)。

    7. この "読み取り、ローカル変更、書き戻し" という流れは、全体的に見ればトランザクションです。 しかし、それを行うためにストレージ トランザクションは使われていません。 "トランザクション" コードはサーバー上でローカルに実行され、分離とアトミック性を確保するためにはサーバーによって IMembershipTable 提供されるオプティミスティック同時実行制御が使われています。

  6. すべてのサイロは、そのデプロイに対するメンバーシップ テーブル全体を定期的に読み取ります。 このようにして、サイロは、新しく参加したサイロと、非稼働と宣言された他のサイロを把握します。

  7. 構成: Azure での運用の間に手動で調整された既定の構成を提供します。 現在、既定では、すべてのサイロが他の 3 つのサイロによって監視され、サイロの非稼働宣言には 2 つの疑いで十分であり、過去 3 分間の疑いのみが考慮されます (それ以外は期限切れになります)。 ping は 10 秒ごとに送信され、サイロを疑うには ping が 3 回失敗する必要があります。

  8. 完全な障害検出の実施 – 理論的には、サイロが他のサイロと通信しなくなって非稼働と宣言されても、サイロのプロセス自体はまだ実行している可能性があります。 この問題を解決するため、サイロがテーブルで非稼働と宣言されたら、非稼働ではない場合であっても (一時的にパーティション分割されたか、ハートビート メッセージが失われただけの場合)、すべてのサイロによって非稼働と見なされます。 すべてのサイロがそのサイロとの通信を停止します。そのサイロは、(テーブルから新しい状態を読み取ることによって) 自分が非稼働であることを知ると、自分自身を強制終了して、そのプロセスをシャットダウンします。 その結果、新しいプロセスとしてサイロを再起動するためのインフラストラクチャが用意されている必要があります (起動時に、新しいエポック番号が生成されます)。 Azure でホストされている場合、それは自動的に行われます。 そうでない場合は、別のインフラストラクチャが必要です。 たとえば、障害時に自動再起動するように構成された Windows サービスや、Kubernetes のデプロイなどです。

  9. 定期的なテーブルの読み取りの頻度を減らし、すべてのサイロによる新規参加サイロと非稼働サイロの認識を高速化するための最適化。 サイロは、テーブルに何か (疑い、新規参加など) を正常に書き込むたびに、他のすべてのサイロに "今すぐテーブルを読み直す" ようブロードキャストします。 サイロは、テーブルに書き込んだ内容を他のサイロに伝えることはなく (この情報は既に古くなっているか間違っている可能性があるため)、テーブルの再読み取りを指示するだけです。 そうすることで、定期的な読み取りサイクルが完全に行われるのを待つ必要なく、メンバーシップの変更を非常に迅速に認識できます。 それでも、"テーブル再読み取り" メッセージが失われた場合のため、定期的な読み取りが必要です。

基本メンバーシップ プロトコルの特徴

  1. 任意の数の障害を処理できる:

    このアルゴリズムは、クラスターの完全な再起動を含め、任意の数の障害を処理できます (つまり f <= n)。 これは、クォーラムを必要とし、通常は多数決である、"従来の" Paxos ベースのソリューションとは対照的です。 運用環境で半分より多くのサイロがダウンした場合を見てきました。 このシステムは機能し続けましたが、Paxos ベースのメンバーシップは続行できませんでした。

  2. テーブルへのトラフィックが非常に軽い:

    実際の ping は、テーブルに対してではなく、サーバー間で直接行われます。 これにより、多くのトラフィックが生成され、障害検出の観点からは正確性が低下します。サイロがテーブルに到達できない場合、稼働ハートビートを書き込むことができず、他のサイロによって強制終了されます。

  3. 正確性と完全性のバランスを調整できる:

    完全な故障検出と正確な故障検出の両方を実現することはできず、通常は、正確性 (稼働しているサイロを非稼働と宣言したくない) と完全性 (実際に稼働していないサイロをできるだけ早く非稼働と宣言したい) のバランスを調整する機能が必要です。 非稼働と ping 失敗を宣言するための構成可能な投票により、それら 2 つを調整できます。 詳しくは、エール大学のコンピューター サイエンスの障害検出機能に関するページをご覧ください。

  4. スケーリング:

    基本的なプロトコルは、数千台のサーバー、おそらくは数万台のサーバーさえ処理できます。 これは、グループ通信プロトコルのような、数十台を超えてスケーリングできないことが知られている従来の Paxos ベースのソリューションとは対照的です。

  5. 診断:

    テーブルは、診断とトラブルシューティングにも非常に便利です。 システム管理者は、現在稼働しているサイロのリストをテーブルですぐに確認できるだけでなく、強制終了されたべてのサイロと疑いの履歴を見ることもできます。 これは、問題を診断するときに特に役立ちます。

  6. IMembershipTable の実装に信頼性の高い永続的ストレージが必要な理由:

    IMembershipTable に永続的ストレージ (Azure テーブル、SQL Server、AWS DynamoDB、Apache ZooKeeper、または Consul IO KV) を使うには、2 つの目的があります。 第一に、サイロの相互検出および Orleans クライアントによるサイロの検出のためのランデブー ポイントとして使われます。 第二に、信頼性の高いストレージを使うと、メンバーシップ ビューで合意を調整するのに役立ちます。 ピアツーピア方式を使ってサイロ間で障害検出を直接実行する一方、メンバーシップ ビューを信頼性の高いストレージに格納し、このストレージによって提供されるコンカレンシー制御メカニズムを使って、稼働サイトと非稼働サイトについて合意します。 このように、ある意味で、このプロトコルは分散コンセンサスの難しい問題をクラウドにアウトソーシングします。 その際、基盤となるクラウド プラットフォームの機能を完全に利用し、それを本当にサービスとしてのプラットフォーム (PaaS) として使います。

  7. しばらくテーブルにアクセスできない場合に発生すること:

    ストレージ サービスが停止しているか、使用できない場合、またはその通信に問題がある場合、Orleans プロトコルは誤ってサイロの非稼働を宣言することはありません。 運用中のサイロは問題なく機能し続けます。 ただし、Orleans はサイロの非稼働を宣言できず (ping の失敗によって一部のサイロが非稼働であると検出された場合、この事実をテーブルに書き込むことはできません)、また、新しいサイロの参加を許可することもできません。 そのため、完全性は損なわれますが、正確性は低下しません。テーブルからパーティション分割しても、Orleans により誤ってサイロの非稼働が宣言されることはありません。 また、ネットワークが部分的にパーティション分割されている場合 (テーブルにアクセスできるサイロとできないサイロがある場合)、Orleans が非稼働のサイロを非稼働であると宣言する可能性がありますが、他のすべてのサイロがそれを認識するまでに時間がかかります。 そのため、検出が遅れる可能性がありますが、テーブルが利用できないために Orleans が誤ってサイロを強制終了することはありません。

  8. 診断のためだけのテーブルへの IAmAlive の直接書き込み:

    サイロ間で送信されるハートビートに加えて、各サイロはテーブル内の自分の行の "稼働中" 列の定期的な更新も行います。 この "稼働中" 列は、手動によるトラブルシューティングと診断にのみ使われ、メンバーシップ プロトコル自体では使われません。 これは、通常、はるかに低い頻度 (5 分に 1 回) で書き込まれ、システム管理者がクラスターの稼働状態を確認したり、サイロが最後に稼働していたときを簡単に知ったりするための非常に便利なツールとして機能します。

メンバーシップ ビューの順序を指定するための拡張機能

上で説明した基本メンバーシップ プロトコルは、その後、メンバーシップ ビューの順序指定をサポートするように拡張されました。 この拡張機能の理由と、その実装方法について簡単に説明します。 この拡張機能では、上記の設計は何も変更されず、すべてのメンバーシップ構成をグローバルに完全に順序指定するプロパティが追加されるだけです。

メンバーシップ ビューの順序を指定すると便利な理由

  • これにより、クラスターへの新しいサイロの参加をシリアル化できます。 それにより、新しいサイロがクラスターに参加するときに、既に開始している他のすべてのサイロへの双方向接続を検証できます。 既に参加しているサイロの一部がそれに応答しない場合 (新しいサイロとのネットワーク接続の問題を示している可能性があります)、新しいサイロの参加は許可されません。 これにより、少なくともサイロの開始時には、クラスター内のすべてのサイロ間に完全な接続があることが確認されます (これが実装されています)。

  • 分散グレイン ディレクトリなど、サイロ内の上位レベルのプロトコルは、メンバーシップ ビューが順番になっているという事実を利用し、この情報を使ってより適切な重複アクティブ化の解決を実行できます。 特に、メンバーシップが流動的だったときに 2 つのアクティブ化が作成されたことがディレクトリで検出されたとき、古くなったメンバーシップ情報に基づいて作成された古い方のアクティブ化を非アクティブ化することが決定される場合があります。

拡張メンバーシップ プロトコル:

  1. この機能の実装では、MembershipTable によって提供される複数の行に対するトランザクションのサポートを利用します。

  2. テーブルの変更を追跡するテーブルに、メンバーシップ バージョンの行を追加します。

  3. サイロ S がサイロ P の疑いまたは非稼働宣言を書き込むとき:

    1. S はテーブルの最新の内容を読み取ります。 P が既に非稼働の場合は、何も行いません。 そうでない場合は、
    2. 同じトランザクションで、P の行に変更を書き込み、バージョン番号をインクリメントして、テーブルに書き戻します。
    3. 両方の書き込みに ETag で条件が設定されます。
    4. P の行またはバージョン行での ETag の不一致が原因でトランザクションが中止された場合は、もう一度試みます。
  4. テーブルへのすべての書き込みで、変更とバージョン行のインクリメントが行われます。 こうすることで、テーブルへの書き込みはすべてシリアル化され (バージョン行の更新をシリアル化することにより)、サイロはバージョン番号をインクリメントするだけなので、書き込みも完全に昇順で順序付けされます。

拡張メンバーシップ プロトコルのスケーラビリティ:

プロトコルの拡張バージョンでは、すべての書き込みが 1 つの行によってシリアル化されます。 これにより、テーブルの同時書き込み間の競合のリスクが高くなるため、クラスター管理プロトコルのスケーラビリティが損なわれる可能性があります。 この問題を部分的に軽減するため、サイロはエクスポネンシャル バックオフを使って、テーブルへのすべての書き込みを再試行します。 最大 200 個のサイロを含む Azure の運用環境で、拡張プロトコルがスムーズに動作することが確認されています。 ただし、サイロが 1,000 個を超えると、プロトコルのスケーリングで問題が発生する可能性があると考えています。 このような大規模な設定では、バージョン行の更新は簡単に無効にされ、基本的にクラスター管理プロトコルの残りの部分が維持されて、全体的な順序指定という特徴は断念される可能性があります。 また、ここで言及しているのはクラスター管理プロトコルのスケーラビリティであり、Orleans の他の部分ではないことに注意してください。 Orleans ランタイムの他の部分 (メッセージング、分散ディレクトリ、グレイン ホスティング、クライアントからゲートウェイへの接続) は、サイロが数百個を超えてもスケーラブルであると考えています。

メンバーシップ テーブル

既に説明したように、IMembershipTable は、サイロがお互いを見つけるため、および Orleans クライアントがサイロを見つけるためのランデブー ポイントとして使われ、メンバーシップ ビューでの合意の調整にも役立ちます。 現在、IMembershipTable には、Azure Table、SQL Server、Apache ZooKeeper、Consul IO、AWS DynamoDB、および開発用のメモリ内エミュレーションのそれぞれに基づく 6 つの実装があります。

  1. Azure Table Storage - この実装では、パーティション キーとして Azure デプロイ ID を使い、行キーとしてサイロ ID (ip:port:epoch) を使います。 これらを組み合わせることで、サイロごとに一意のキーが保証されます。 コンカレンシー制御については、Azure Table ETags に基づくオプティミスティック同時実行制御を使います。 テーブルから読み取るたびに、読み取られた行ごとに ETag を格納し、書き戻しを試みるときはその ETag を使います。 ETag は、書き込みごとに Azure Table サービスによって自動的に割り当てられ、チェックされます。 複数行トランザクションの場合は、Azure テーブルによって提供されるバッチ トランザクションのサポートを利用します。これにより、同じパーティション キーを持つ行に対してシリアル化可能なトランザクションが保証されます。

  2. SQL Server - この実装では、構成されているデプロイ ID を使って、デプロイが区別され、どのサイロがどのデプロイに属しているかが識別されます。 サイロ ID は、適切なテーブルと列の deploymentID, ip, port, epoch の組み合わせとして定義されます。 Azure Table の実装で ETags を使う手順と同様に、リレーショナル バックエンドはオプティミスティック同時実行制御とトランザクションを使います。 リレーショナルの実装では、使われる ETag はデータベース エンジンによって生成するものと想定されます。 SQL Server の場合、SQL Server 2000 では、生成される ETag は NEWID() の呼び出しから取得されるものです。 SQL Server 2005 以降では、ROWVERSION が使われます。 Orleans は、リレーショナル ETag を非透過的な VARBINARY(16) タグとして読み書きし、base64 でエンコードされた文字列としてメモリに格納します。 Orleans では、統計データの挿入に現在使われている、UNION ALL (Oracle の場合は DUAL を含む) を使った複数行の挿入がサポートされています。 SQL Server 向けの正確な実装と原理については、CreateOrleansTables_SqlServer.sql をご覧ください。

  3. Apache ZooKeeper - この実装では、構成されたデプロイ ID をルート ノードとして使い、サイロ ID (ip:port@epoch) を子ノードとして使います。 これらを組み合わせることで、サイロごとに一意のパスが保証されます。 コンカレンシー制御については、ノードバージョンに基づくオプティミスティック同時実行制御を使います。 デプロイ ルート ノードから読み取るたびに、すべての読み取り子サイロ ノードのバージョンを格納し、書き戻すときはそのバージョンを使います。 ノードのデータが変化するたびに、ZooKeeper サービスによってバージョン番号がアトミックに増やされます。 複数行トランザクションの場合は、multi メソッドを利用します。これにより、同じ親デプロイ ID ノードを持つサイロ ノードに対してシリアル化可能なトランザクションが保証されます。

  4. Consul IO - Consul のキーと値のストアを使って、メンバーシップ テーブルを実装しました。 詳しくは、Consul のデプロイに関する記事をご覧ください。

  5. AWS DynamoDB - この実装では、クラスター デプロイ ID をパーティション キーとして使い、レコードを一意にする RangeKey としてサイロ ID (ip-port-generation) を使います。 オプティミスティック同時実行制御は、DynamoDB で条件付き書き込みを行うことで、ETag 属性によって行われます。 実装ロジックは、Azure Table Storage とよく似ています。

  6. 開発セットアップ用のメモリ内エミュレーション。 その実装には、MembershipTableGrain と呼ばれる特殊なシステム グレインを使っています。 このグレインは、開発セットアップにのみ使われる、指定されたプライマリ サイロに存在します。 実際の運用環境で使う場合、プライマリ サイロは必要ありません

構成

メンバーシップ プロトコルは、OrleansConfiguration.xml ファイルの Globals セクションの Liveness 要素を使って構成されます。 既定値は Azure の運用環境での何年もの使用に基づいて調整されており、適切な既定の設定を表していると考えています。 一般に変更する必要はありません。

サンプル構成要素:

<Liveness ProbeTimeout="5s"
    TableRefreshTimeout="10s"
    DeathVoteExpirationTimeout="80s"
    NumMissedProbesLimit="3"
    NumProbedSilos="3"
    NumVotesForDeathDeclaration="2" />

4 種類の稼働状態が実装されています。 稼働状態プロトコルの種類は、OrleansConfiguration.xml ファイルの Globals セクションの SystemStore 要素の SystemStoreType 属性を使って構成されます。

  1. MembershipTableGrain: メンバーシップ テーブルは、プライマリ サイロのグレインに格納されます。 これは、開発用セットアップ専用です。
  2. AzureTable: メンバーシップ テーブルは Azure テーブルに格納されます。
  3. SqlServer: メンバーシップ テーブルはリレーショナル データベースに格納されます。
  4. ZooKeeper: メンバーシップ テーブルは ZooKeeper のアンサンブルに格納されます。
  5. Consul: MembershipTableAssembly = "OrleansConsulUtils" を使ってカスタム システム ストアとして構成されます。 詳しくは、Consul のデプロイに関する記事をご覧ください。
  6. DynamoDB: MembershipTableAssembly = "OrleansAWSUtils" を使ってカスタム システム ストアとして構成されます。

すべての稼働状態の種類に共通の構成変数が、Globals.Liveness 要素で定義されています。

  1. ProbeTimeout: 他のサイロの稼働状態をプローブする秒数、またはサイロが自身に関する "稼働中" ハートビート メッセージを送信するための秒数。 既定値は 10 秒です。
  2. TableRefreshTimeout: メンバーシップ テーブルから更新をフェッチする秒数。 既定値は 60 秒です。
  3. DeathVoteExpirationTimeout: メンバーシップ テーブルでの非稼働投票の有効期限 (秒)。 既定値は 120 秒です
  4. NumMissedProbesLimit: このサイロが非稼働であると疑われるようになる、サイロからの "稼働中" ハートビート メッセージの受信失敗回数、または未応答プローブの数。 既定値は 3 です。
  5. NumProbedSilos: 各サイロが各稼働状態をプローブするサイロの数。 既定値は 3 です。
  6. NumVotesForDeathDeclaration: サイロを非稼働として宣言するために必要な期限切れでない投票の数 (NumMissedProbesLimit 以下にする必要があります)。 既定値は 2 です。
  7. UseLivenessGossip: 稼働状態情報の拡散を高速化するためにゴシップ最適化を使うかどうか。 既定値は true です。
  8. IAmAliveTablePublishTimeout: このサイロが稼働していることをメンバーシップ テーブルに定期的に書き込む間隔の秒数。 診断にのみ使われます。 既定値は 5 分です。
  9. NumMissedTableIAmAliveLimit: 警告がログに記録される、サイロからのテーブルの "稼働中" 更新失敗の回数。 稼働状態プロトコルには影響しません。 既定値は 2 です。
  10. MaxJoinAttemptTime: サイロのクラスターへの参加の試みを中止するまでの秒数。 既定値は 5 分です。
  11. ExpectedClusterSize: クラスターの予想されるサイズ。 それほど正確である必要はなく、過大に評価してもかまいません. Azure テーブルへの書き込みを再試行するときのエクスポネンシャル バックオフ アルゴリズムを調整するために使われます。 既定値は 20 です。

設計の原理

よくある疑問として、クラスター メンバーシップの実装を Apache ZooKeeper に完全に依存しないのはなぜでしょうか。エフェメラル ノードによるグループ メンバーシップのためのすぐに使用できるサポートを使う可能性はないのでしょうか。 なぜメンバーシップ プロトコルの実装に苦労したのでしょうか。 主に次の 3 つの理由がありました。

  1. クラウドでのデプロイとホスティング:

    Zookeeper はホスト型サービスではありません (少なくともこれを書いている 2015 年 7 月の時点では、そして 2011 年の夏にこのプロトコルを初めて実装したときには間違いなく、主要なクラウド プロバイダーによってホスト型サービスとして実行される Zookeeper のバージョンはありませんでした)。 つまり、クラウド環境では、Orleans のお客様は ZK クラスターのインスタンスを自分でデプロイ、実行、管理する必要があります。 これは、お客様に無理強いしたくなかった不必要な負担の 1 つに過ぎません。 Azure Table を使うことで、ホスト型のマネージド サービスを利用でき、お客様の作業ははるかに簡単になります。 基本的に、クラウドでは、インフラストラクチャとしてではなく、プラットフォームとしてクラウドを使用します。 一方、サーバーをオンプレミスで実行して管理する場合は、IMembershipTable の実装として ZK に依存するのが実行可能なオプションです。

  2. 直接的な障害検出:

    エフェメラル ノードで ZK のグループ メンバーシップを使った場合、障害検出は Orleans サーバー (ZK クライアント) と ZK サーバーの間で実行されます。 これは、必ずしも Orleans サーバー間の実際のネットワークの問題と関連付けられるとは限りません。 開発者が目指したのは、障害検出にクラスター内の通信状態を正確に反映させることでした。 具体的には、この設計では、Orleans のサイロが IMembershipTable と通信できない場合は、非稼働とは見なされず、動作を続けることができます。 これに対し、エフェメラル ノードで ZK のグループ メンバーシップを使った場合は、ZK サーバーから切断されると、稼働していて完全に機能する可能性があっても、Orleans サイロ (ZK クライアント) が非稼働と宣言される場合があります。

  3. 移植性と柔軟性:

    Orleans の哲学の一環として、特定の技術への強い依存を強制するのではなく、異なるコンポーネントを異なる実装で簡単に切り替えることができる柔軟な設計が望まれます。 これはまさに IMembershipTable の抽象化が果たす目的です。

謝辞

このプロトコルの最初のバージョンの設計と実装に対する Alex Kogan の貢献に感謝します。 この作業は、2011 年夏の Microsoft Research での夏期インターンシップの一環として行われました。 ZooKeeper ベースの IMembershipTable の実装は、Shay Hazor によって行われました。SQL での IMembershipTable の実装は、Veikko Eeva によって行われました。AWS DynamoDB での IMembershipTable の実装は、Gutemberg Ribeiro によって行われました。Consul ベースの IMembershipTable の実装は、Paul North によって行われました。