次の方法で共有


Orleans ストリームの実装詳細

このセクションでは、 Orleans Stream の実装の概要について説明します。 アプリケーション レベルでは表示されない概念と詳細について説明します。 ストリームのみを使用する場合は、このセクションを読む必要はありません。

用語:

ストリーム イベントを取り込み、イベントをプルしたり、イベントを使用するためのプッシュベースのメカニズムを提供したりできる、持続性のあるストレージ テクノロジを "queue" という単語で参照します。 通常、スケーラビリティを提供するために、これらのテクノロジはシャード化/パーティション分割されたキューを提供します。 たとえば、Azure キューでは複数のキューを作成でき、Event Hubs には複数のハブがあります。

永続ストリーム

すべての Orleans 永続ストリーム プロバイダーは、共通の実装 PersistentStreamProviderを共有します。 これらの汎用ストリーム プロバイダーは、テクノロジ固有の IQueueAdapterFactoryで構成する必要があります。

たとえば、テスト目的で、キューからデータを読み取るのではなく、テスト データを生成するキュー アダプターがあります。 次のコードは、カスタム (ジェネレーター) キュー アダプターを使用するように永続的なストリーム プロバイダーを構成する方法を示しています。 これを行うには、アダプターの作成に使用するファクトリ関数を使用して永続的なストリーム プロバイダーを構成します。

hostBuilder.AddPersistentStreams(
    StreamProviderName, GeneratorAdapterFactory.Create);

ストリーム プロデューサーが新しいストリーム項目を生成し、 stream.OnNext()を呼び出すと、 Orleans ストリーミング ランタイムは、そのストリーム プロバイダーの IQueueAdapter で適切なメソッドを呼び出し、適切なキューに項目を直接エンキューします。

プル エージェント

永続ストリーム プロバイダーの中核となるのがプル エージェントです。 プル エージェントは、一連の永続キューからイベントを取得し、それらを消費するグレインを含むアプリケーションコードに配信します。 プルエージェントは、分散された「マイクロサービス」として考えることができ、それはパーティション化され、高可用性かつエラスティックな分散コンポーネントです。 プル エージェントは、アプリケーション グレインをホストする場合と同じサイロ内で実行され、Orleans ストリーミング ランタイムによって全面的に管理されます。

StreamQueueMapperStreamQueueBalancer

プル エージェントは、 IStreamQueueMapperIStreamQueueBalancerを使用してパラメーター化されます。 IStreamQueueMapperは、すべてのキューの一覧を提供し、ストリームをキューにマッピングする役割も担います。 こうすることで、永続ストリーム プロバイダーのプロデューサーは、どのキューにメッセージを追加するかを知ることができます。

IStreamQueueBalancerは、Orleansサイロとエージェント間でキューのバランスを取る方法を表します。 目標は、ボトルネックを防ぎ、弾力性をサポートするために、バランスのとれた方法でエージェントにキューを割り当てることです。 Orleans クラスターに新しいサイロが追加されると、キューは古いサイロと新しいサイロ間で自動的に再調整されます。 StreamQueueBalancerでは、そのプロセスをカスタマイズできます。 Orleans には、さまざまな分散シナリオ (多数および少数のキュー) と異なる環境 (Azure、オンプレミス、静的) をサポートするために、複数の StreamQueueBalancers が組み込まれています。

上記のテスト ジェネレーターの例を使用して、次のコードは、キュー マッパーとキュー バランサーを構成する方法を示しています。

hostBuilder
    .AddPersistentStreams(StreamProviderName, GeneratorAdapterFactory.Create,
        providerConfigurator =>
        providerConfigurator.Configure<HashRingStreamQueueMapperOptions>(
            ob => ob.Configure(options => options.TotalQueueCount = 8))
      .UseDynamicClusterConfigDeploymentBalancer());

上記のコードでは、8 つのキューを持つキュー マッパーを使用するように GeneratorAdapterFactory を構成し、 DynamicClusterConfigDeploymentBalancerを使用してクラスター全体でキューのバランスを取ります。

プル プロトコル

各サイロは一連のプル エージェントを実行し、各エージェントは 1 つのキューからプルします。 プル エージェント自体は、 SystemTarget と呼ばれる内部ランタイム コンポーネントによって実装されます。 SystemTargets は基本的にランタイム グレインであり、シングル スレッドコンカレンシーの対象であり、通常のグレイン メッセージングを使用でき、グレインと同じくらい軽量です。 グレインとは対照的に、SystemTargets は仮想ではありません。SystemTargets は明示的に (ランタイムによって) 作成され、場所は透過性ではありません。 プル エージェントを SystemTargets として実装することで、 Orleans ストリーミング ランタイムは組み込みの Orleans 機能に依存でき、新しいプル エージェントの作成は新しいグレインの作成と同じくらい安価であるため、非常に多くのキューにスケーリングできます。

すべてのプル エージェントは、 IQueueAdapterReceiver.GetQueueMessagesAsync メソッドを呼び出してキューからプルする定期的なタイマーを実行します。 返されたメッセージは、 IQueueCacheと呼ばれるエージェントごとの内部データ構造に格納されます。 すべてのメッセージが検査され、その宛先ストリームが見つかります。 エージェントは、Pub-Sub を使用して、このストリームをサブスクライブしているストリーム コンシューマーの一覧を確認します。 コンシューマー リストが取得されると、エージェントはローカルに (その pub-sub キャッシュに) 格納するため、すべてのメッセージで Pub-Sub を参照する必要はありません。 また、エージェントは pub-sub をサブスクライブして、そのストリームをサブスクライブする新しいコンシューマーの通知を受信します。 エージェントと pub-sub の間のこのハンドシェイクにより 、強力なストリーミング サブスクリプション セマンティクスが保証されます。コンシューマーがストリームをサブスクライブすると、サブスクライブ後に生成されたすべてのイベントが表示されます。 さらに、StreamSequenceToken を使用すると、過去でのサブスクライブが可能になります。

キュー キャッシュ

IQueueCache は、キューから新しいイベントのデキューを切り離してコンシューマーに配信できるようにする、エージェントごとの内部データ構造です。 また、異なるストリームと異なるコンシューマーへの配信を切り離すこともできます。

1 つのストリームに 3 つのストリーム コンシューマーがあり、そのうちの 1 つが低速である状況を想像してください。 注意を払わないと、この低速なコンシューマーがエージェントの進行状況に影響し、そのストリームの他のコンシューマーの消費が遅くなり、さらに他のストリームのイベントのデキューと配信が遅くなる可能性があります。 これを防ぎ、エージェントで最大限の並列処理を可能にするために、 IQueueCacheを使用します。

IQueueCache はストリーム イベントをバッファーに格納し、エージェントが独自のペースで各コンシューマーにイベントを配信する方法を提供します。 コンシューマーごとの配信は、コンシューマーごとの進行状況を追跡する IQueueCacheCursor と呼ばれる内部コンポーネントによって実装されます。 こうすることで、各コンシューマーは独自のペースでイベントを受け取ります。高速コンシューマーはキューからデキューされるのと同じ速さでイベントを受信し、低速コンシューマーは後でイベントを受信します。 メッセージがすべてのコンシューマーに配信されると、キャッシュから削除できます。

バックプレッシャ

Orleans ストリーミング ランタイムのバックプレッシャは、キューからエージェントにストリーム イベントを取り込み、エージェントからストリーム コンシューマーにイベントを配信する 2 つの場所に適用されます。

後者は、組み込みの Orleans メッセージ配信メカニズムによって提供されます。 すべてのストリーム イベントは、一度に 1 つずつ、標準の Orleans グレイン メッセージングを介して、エージェントからコンシューマーに配信されます。 つまり、エージェントは各ストリーム コンシューマーに 1 つのイベント (またはイベントの限られたサイズのバッチ) を送信し、この呼び出しを待機します。 前のイベントのタスクが解決または破損するまで、次のイベントの配信は開始されません。 このように、コンシューマーごとの配信レートは一度に 1 つのメッセージに制限されます。

キューからエージェントにストリーム イベントを取り込む場合、 Orleans ストリーミングには新しい特殊なバックプレッシャ メカニズムが用意されています。 エージェントはキューからのイベントのデキューとコンシューマーへの配信を切り離すため、単一の低速コンシューマーが大幅に遅れて、IQueueCache がいっぱいになる可能性があります。 IQueueCacheが無期限に増加するのを防ぐために、サイズを制限します (サイズ制限は構成可能です)。 ただし、エージェントは配信不能イベントを捨てません。

代わりに、キャッシュがいっぱいになると、エージェントはキューからのイベントのデキュー速度を遅くします。 そうすることで、キューから消費する速度 ("バックプレッシャ") を調整して、遅い配信期間を "乗り切る" ことができます。また、後で高速消費率に戻ることができます。 "低速配信" 谷を検出するために、 IQueueCache は、個々のストリーム コンシューマーへのイベント配信の進行状況を追跡するキャッシュ バケットの内部データ構造を使用します。 これにより、非常に応答性の高い自己調整システムになります。