2016-05-02 6 views
5

プロデューサが消費者が消費するよりもはるかに速い生産者 - 消費者シナリオがあります。一般的には、プロデューサ/コンシューマシナリオが最も遅いコンポーネントほど高速に動作するため、ソリューションはプロデューサをブロックすることです。私たちのアプリケーションは、消費者が後で追いつくのに十分な時間を提供するので、生産者のスロットルまたはブロックはではなく、です。ここで速いプロデューサ、遅いコンシューマのためのJavaの "階層化されたキュー"実装

は、より一般的なシナリオ対我々のアプリケーションでは、完全な「フェーズ」を描いた図です:

 Our Application     Common Scenario 
2N +--------+--------+ 
    |PPPPPPPP|oooooooo|           P = Producer 
    |PPPPPPPP|oooooooo|           C = Consumer 
    N +--------+--------+  N +--------+--------+--------+  o = Other Work 
    |CPCPCPCP|CCCCCCCC|  |CPCPCPCP|CPCPCPCP|oooooooo|  N = number of tasks 
    |CPCPCPCP|CCCCCCCC|  |CPCPCPCP|CPCPCPCP|oooooooo| 
    -------------------  ---------------------------- 
    0  T/2  T  0  T/2  T  3T/2 

アイデアが生産を阻害しないことにより、スループットを最大化することです。

私たちのタスクが動作するデータは簡単にシリアライズされるので、すぐには満たせないすべてのタスクをスピルアップするためのファイルシステムソリューションを実装する予定です。

私はメモリが不足しないように最大容量のBlockingQueueでJavaのThreadPoolExecutorを使用しています。問題は、メモリにキューイングできるタスクがすぐに実行されるような「階層型」キューを実装することです。それ以外の場合は、データがディスク上にキューイングされます。

私は2つの可能な解決策を作ってみた:

  1. を基準としてLinkedBlockingQueueまたはArrayBlockingQueue実装を使用して、ゼロからBlockingQueueを実装します。これは、標準ライブラリの実装をコピーし、ファイルシステムの読み書きを追加するのと同じくらい簡単です。
  2. 標準BlockingQueueの実装を継続し、データを格納するために別のFilesystemQueueを実装し、ファイルをデキューするために1つ以上のスレッドを使用してRunnableを作成し、ThreadPoolExecutorを使用してエンキューします。

これらのいずれかが妥当であり、潜在的により良いアプローチですか?

答えて

2

最初のオプションは、例えば、メモリフラグ-Xmxを使用して、増加 Dimitrovのディミタールによって示唆として入手ヒープ領域のサイズ、ですjava -Xmx2048m

投稿者Oracle's Documentation:JVMは、ヒープ以外のメモリを使用することに注意してください。たとえば、 Javaのメソッド、スレッドスタック、およびネイティブハンドルは、ヒープとは別のメモリ とJVMの内部データ構造体に割り当てられます。ここで

また、Java ヒープメモリを分類しているかを示す図です。

enter image description here


番目のオプションは、要求された機能を実装したライブラリを使用することです。その目的のために、あなたはプロジェクトの概要からashes-queue

を使用することができます。これは、永続的なサポートを持つJava で、単純なFIFOの実装です。つまり、キューがいっぱいになると、メッセージがあふれているので、 スロットが利用可能になると、それらはメモリに戻されます。


番目のオプションは、独自の実装を作成にあります。その点については、その目的のためにあなたを導くthis threadをプレビューすることができます。

この最後の3番目のオプションには、が含まれています。どちらも合理的です。実装の観点から見ると、実装が簡単でデザインがクリーンであることが保証されるため、最初のオプションを選択する必要があります。

2

ファイルシステムではなく、JMSキューを使用するのが理想的です。

ブロッキングキューを使用する代わりに、永続的なJMSキューにメッセージを送信します。 BlockingQueueと並行してJMSキューを結合し、BlockingQueueがいっぱいになったときにJMSキューに投稿するという段階的なアプローチを試すことはできますが、純粋なJMSアプローチはそれだけでうまくいくと思います。

4

もっと複雑な解決策を開始する前に、限定されたBlockingQueueを使用すると、あなたのためのディール・ブレーカーとなると確信していますか?あなたのヒープサイズを大きくし、十分な容量をあらかじめ割り当てることは、あなたにとってはまだOKです。快適さの範囲内にあるGC停止の代償として、複雑さとパフォーマンスの不確実性を避けることができます。

あなたの作業負荷が不平等であるため、(MPMCブロッキングキューと比較して)メモリに収まらない量のメッセージを永続させることができる場合は、より簡潔で小さなバージョンのActiveMQまたはそのオフフートのApolloアプリケーションに応じて、ActiveMQの他の機能が役立つかもしれませんが、その場合は直接使用できます。そうでない場合は、bowmoreが示唆するように、おそらくJMSスペースの検索をお勧めします。

関連する問題