Clojure ネットワーク アプリケーションがあります。基本的な構造は次のようになります。
- サーバーにはLinkedBlockingQueueまたはArrayBlockingQueueが1つあります(両方を試しました)
- 複数のスレッドがネットワーク接続を受け入れ
offer
、キューに対して動作します take
無限ループでキューから1 つのスレッドを取得し、取得した各アイテムで作業します
そして、take
呼び出しで重大なパフォーマンスの問題に気付きました:
- スレッドは
offer
非常に速い速度でキューに送られ、キューはそれらすべてを非常に迅速に処理します - キューからの 1 つのワーカー スレッド
take
の速度が非常に遅い (の速度の 200 倍以上遅いoffer
) - CPU 使用率が非常に低いため、ワーカーはまったくビジーではありません
キューを使用しない場合、ベンチマークの状況では、同じワークロードが CPU 使用率を最大化し、満足のいく速度で実行できます。
では、このシナリオで使用するのに最適なキューイング手法は何でしょうか?
これが私のコードです(100行未満)。
https://github.com/HouzuoGuo/Aurinko/blob/master/src/Aurinko/core.clj
編集、私の観察の詳細:
- リクエスト処理速度のベンチマークを行ったところ、キューを使用せずに 1 秒あたり約 8,000 リクエストで動作しました。
- サーバー プログラムがリクエストをキューに入れるときにデバッグ メッセージを出力し、リクエストの処理が終了すると別のメッセージを出力するようにしました。
- 毎秒約 1,000 件のリクエストをサーバーに送信する簡単なクライアント プログラムを作成しました。
- サーバーは時間内にすべての要求をキューに入れ、キューは何千もの要素の長さになります。
- デバッグ メッセージによると、ワーカー (リクエスト プロセッサ) は 1 秒あたり約 150 リクエストしか処理していないようです。
編集:
みんなの助けに感謝します。ブロッキング キューがパフォーマンスの問題の原因ではないことを確認しました。アプリケーションにパフォーマンスのボトルネックは見つかりませんでしたが、どこかにあるはずです。
最終編集:
みんなありがとう。パフォーマンスのボトルネックは、ブロッキング キューではなく、ネットワーク IO が原因でした。