1. ホーム

[解決済み】LMAXのディスラプターパターンはどのように機能するのですか?

2022-04-10 19:17:31

質問

を理解しようとしています。 ディスラプターパターン . InfoQのビデオを見たり、彼らの論文を読んでみたりしました。リングバッファが関係しており、キャッシュの局所性を利用するために非常に大きな配列として初期化され、新しいメモリの割り当てが不要になると理解しています。

位置を記録するアトミック整数が1つ以上あるようですね。各「イベント」はユニークなIDを持ち、リングのサイズに対するモジュラスを求めることで、リング内の位置を見つけることができるようです。

残念ながら、その仕組みを直感的に理解することはできません。トレーディングのアプリケーションをたくさんやって、勉強してきたのですが アクターモデル とか、SEDAを見た、などなど。

プレゼンでは、このパターンは基本的にルーターの仕組みだと言っていましたが、ルーターの仕組みの良い説明も見つかりませんでした。

何か良い解説のポインターはないでしょうか?

どのように解決するのですか?

Google Codeプロジェクトでは 技術論文への言及 リングバッファの実装についてですが、少しドライでアカデミックな内容で、その仕組みを学びたい人にとっては厳しい内容です。しかし、より読みやすい方法で内部を説明し始めたブログ記事がいくつかあります。また リングバッファの説明 は、ディスラプターパターンの核である 消費者バリアに関する記述 (ディスラプターから読み取ることに関連する部分)と、いくつかの 複数の生産者の対応に関する情報 が利用できます。

Disruptor を簡単に説明すると、スレッド間で最も効率的にメッセージを送信する方法です。キューの代わりとして使うことができますが、SEDAやActorと多くの機能を共有しています。

キューと比較すると

Disruptor はメッセージを他のスレッドに渡し、必要ならそれを起動する機能を提供します (BlockingQueue と同様)。しかし、3つの明確な違いがあります。

  1. Disruptor のユーザは Entry クラスを拡張し、事前割り当てを行うファクトリを提供することで、メッセージの格納方法を定義します。これにより、メモリの再利用(コピー)や、Entryに他のオブジェクトへの参照を持たせることができるようになります。
  2. まずリングバッファにスロットが要求され、適切なデータを入力できるエントリがユーザに提供されます。この2段階のアプローチは、前述のメモリの柔軟な使用を可能にするために必要です。コンシューマースレッドからメッセージを見えるようにするのはコミットです。
  3. リングバッファから消費されたメッセージを追跡するのは、コンシューマの責任です。この責任をリングバッファ自体から取り除くことで、各スレッドが自分自身のカウンターを維持するため、書き込み競合の量を減らすことができました。

アクターとの比較

Actorモデルは、特に提供されているBatchConsumer/BatchHandlerクラスを使用する場合、他の多くのプログラミングモデルよりもDisruptorに近くなります。これらのクラスは、消費されるシーケンス番号を管理する複雑さをすべて隠し、重要なイベントが発生したときに単純なコールバックのセットを提供します。しかし、いくつかの微妙な違いがあります。

  1. Disruptor は 1 スレッド - 1 コンシューマーモデルを使用し、Actor は N:M モデルを使用します。つまり、好きなだけアクターを持つことができ、それらは一定のスレッド数 (通常 1 コア) に分散されます。
  2. BatchHandler インターフェースは、追加の(そして非常に重要な)コールバックを提供します。 onEndOfBatch() . これにより、低速のコンシューマ、例えばI/Oを行うコンシューマは、スループットを向上させるためにイベントを一括して処理することができます。他のActorフレームワークでもバッチ処理を行うことは可能ですが、他のフレームワークのほとんどはバッチの終了時にコールバックを提供しないため、バッチの終了を判断するためにタイムアウトを使用する必要があり、結果としてレイテンシーが悪くなります。

SEDAとの比較

LMAXは、SEDAベースのアプローチを置き換えるために、Disruptorパターンを構築しました。

  1. SEDAと比べた主な改善点は、並行して作業を行うことができることです。これを実現するために、Disruptorは複数のコンシューマに同じメッセージを(同じ順序で)マルチキャストすることをサポートしています。これにより、パイプラインのフォークステージが不要になります。
  2. また、コンシューマは他のコンシューマの結果を、間に別のキューイング・ステージを入れることなく待つことができます。コンシューマは、単に依存しているコンシューマのシーケンス番号を見るだけでよいのです。これにより、パイプラインのジョインステージが不要になります。

メモリバリアと比較した場合

もう1つの考え方は、構造化され、順序付けられたメモリバリアです。生産者バリアが書き込みバリアを形成し、消費者バリアが読み込みバリアを形成します。