2011-11-15 18 views
5

私は、ユーザーリクエストを処理し、ミドルウェアと話し合い、応答を送信するnettyに実装されたサーバーを持っています。 I/Oは、ミドルウェアへのラウンドトリップに比べて無視できると予想されるため、ブロックを最小限に抑えるため、OrderedMemoryAwareThreadPoolExecutorの上にあるパイプラインにExecutionHandlerがあります。これまでのところ問題はありません。ThreadPoolExecutorsでのNettyタスクの優先順位付け

負荷の高い状態でのサーバーの動作を見ています。私たちのプロトコルの過去の経験から、私たちは偶発的なDOS攻撃に悩まされがちです。ほとんどの場合、ユーザのスクリプトは無限ループに似ています。理想的には、チャンネルが特定の使用率しきい値を超えたときに優先順位を解除し、他のユーザーのサービスに影響を与えないようにすることができます。

私は、PriorityBlockingQueueを使用する単純なThreadPoolExecutorを実装し、独自のSessionクラス(ChannelHandlerのコンテキストに添付)から抽出されたデータに基づいて優先順位を設定します。もう一度、これまでのところ問題はありません。

Nettyの組み込みThreadPoolExecutorsの順序付けとメモリ認識を利用しようとすると、問題が発生します。理想的には、MyThreadPoolExecutorは、OrderedMemoryAwareThreadPoolExecutorを拡張して、優先順位のキューに入れることができます。悲しいことに、プライベートとファイナルの2つの理由からこれは不可能です。より詳細には:

A)ThreadPoolExecutor.workQueueはそのコンストラクタで設定することができますが、LinkedTransferQueueとしてMemoryAwareThreadPoolExecutorがハードコードこの、およびその子にこれを公開しないOrderedMemoryAwareThreadPoolExecutor(すなわちMyThreadPoolExecutorを設定するためのアクセス権を持っていませんそれ)。必要に応じて、これは反射ベースのプライベートフィールド調整の醜いビットで克服することができます。

b)MyThreadPoolExecutor.doUnorderedExecute()をオーバーライドして、優先処理を挿入して必要なオブジェクトを構築できるようにしたいと思いますが、final宣言しました。それを呼び出すコードは変更する必要はありません。

解決済みの点は、すてきなネットフィーチャを保つことですが、優先度キューを使用すると、OrderedMemoryAwareThreadPoolExecutorとMemoryAwareThreadPoolExecutorの両方をコピーして、それぞれの行を調整してそこから拡張する必要があります。これは良いコーディング練習として私を攻撃しない!それを考慮しても、警鐘を放つ。今、いくつかの質問に

1)私が間違っている問題を解決するだろうか?私が達成したいことを間違った木全体を吠えるか?

2)そうでない場合は、上記の方法よりも良い方法がありますか?

3)上記のアプローチでは、サーバーの負荷の合計が一貫して不足している優先度の低いタスクでは、枯渇する危険性があります。私は「いたずらな」ユーザーのためにこれを容認する用意ができていますが、通常の状態に戻ったらすぐに既存のタスクは飢えていて、順序を保持するために新しい優先度の高いタスクを追加する必要があります。これに対処する最良の方法についての推奨事項はありますか? (禁止のユーザーはビジネスで許可されていません)

4)半分質問です。 OrderedMemoryAwareThreadPoolExecutorのnettyドキュメントには、スレッドXの便利な図があります& Y - おそらくこれらはThreadPoolExecutorにプールされ、I/Oワーカースレッドではないスレッドですか?これをもっと明確にする価値があります。また、ExecutionHandlerを使用しない場合、各チャネルは単一のI/Oワーカースレッドにバインドされます.ExecutionHandlerの背後にある場合でもこれが当てはまりますか?つまり、チャネルに到着した順序と同じになることが保証されたExecutionHandlerにタスクが追加される順序ですか?この場合、MemoryAwareThreadPoolExecutorのドキュメントのスレッドXがイベント1よりも前にイベント2を処理する方法がわかりません - ここでは別のスレッドが任意の順序で作業を完了できますが、その作業がどのようにできるかはわかりません順番に同じスレッドに割り当てられます(workQueueからポップします)。 ExecutionHandlerのドキュメントでは、このことについてヒントがありますが、もう少し詳しくお話してください。

お読みいただきありがとうございました。ご協力いただければ幸いです。

答えて

0

あなたの「アラーム音」ソリューションはよく知られています。小さいプールサイズから始めてください。

あなたは、遅いサーバーの解決策が必要だと言っているようです。 サーバが負荷を受けて低速になっている理由を調べることをお勧めします。 - スレッド競合(競争)問題。 - 初期プールサイズ - GC設定

+2

このサーバーはまだ開発中ですが、置き換えられる(C++)サーバーは強くデータベースにバインドされています。私たちは、ワーカースレッドのプールが限られているため、データベースの負荷が高い(悪いニュース)可能性を解決しましたが、これは、1人の空腹のユーザーがすべてのワーカーをチャンプ化し、他の人のサービスを悪化させる可能性を認めました維持するために非常にタイトなSLA)。古いサーバーでのこの問題に対する私たちの解決策は、ネットの下に保持されていない仮定に基づいていたので、何か良い点を考え出す必要があります。私たちはまだプールのサイズを心配していません! – Liche

3

1)いいえ、あなたはいいですね。そのような機能が欠けているのはちょうどOrderedMemoryAwareThreadPoolExecutorです。あなたfile an issueでしょうか?

2)私はちょうどOrderedMemoryAwareThreadPoolExecutorをフォークして簡略化し、優先度キューを追加します。そうすれば、キュー項目(イベント)の処理方法をはるかに制御できます。

3)優先度キューを使用する代わりに、優先度が高い項目と優先度の低い項目の2つのキューを持つことができます。スレッドは優先順位の高いキューを最初に処理することができますが、ループを制御して長すぎないようにすることができます。

4)はい、それらはThreadPoolExecutorのスレッドです。明確でない場合は、ドキュメントを更新する必要があります。お気軽に問題を提出するか、それをフォークして直接貢献してください。

+0

ありがとう、私はこれらの変更に踏み込んでしまいます。私が雇用主からの許可を得ると、私はそれをプロジェクトに正式に提出します。 – Liche

+0

2つのキューまたはPriorityQueueよりも洗練されたソリューションを提案します。 OMATPEは、メインのworkQueueを介してチャネルのタスクのキューがワーカーに与えられるように実装されています。ワーカーは、そのチャネルのすべてのタスク(および平均時間内に追加されたものすべて)を実行して戻り、別のチャネルの作業を取得します。したがって、ビジーなチャネルはワーカーを独占することができます。したがって、優先度の低いチャネルの場合、固定数のタスクまで処理してから、workQueueの末尾に戻します。したがって、それは飢えずに処理されますが、どれくらいリソースを奪うことができるかという上限があります。 (ただし、余分なオーバーヘッド。) – Liche

関連する問題