コード
TCP トラフィックをリッスンし、バイナリ データを JSON 形式に解析するクラスター ノード アプリケーションがあります。
しかし、ここに問題があります。すべての着信トラフィックは、単一の永続的な接続を通過します。
私が理解しているように、クラスターはワーカー間で新しいソケットを分散することによって単一ポートの負荷を分散しますが、単一ソケットの負荷をワーカー間で分散するネイティブな方法はありません。
そのために、着信接続を受け入れてメッセージをセグメント化するようにクラスター マスターをセットアップしました。次に、ラウンド ロビン方式でクラスター ワーカーにメッセージを明示的に渡します。メッセージのセグメント化を担当するストリームが新しいメッセージを発行するときsend
、次のワーカー/パーサーへのメッセージにクラスター メッセージング API を使用するだけです。
// (cluster.isMaster === true)
var gateway = new Gateway(config.gateway.port, config.gateway.host);
var nextWorker = 1;
gateway.on('message', function roundRobin (msg) {
var workers = cluster.workers;
var numWorkers = Object.keys(workers).length;
workers[nextWorker].send(msg);
if (++nextWorker > numWorkers) {
nextWorker = 1; // else, it's prefix incremented
}
});
for (w in cluster.workers) {
cluster.workers[w].on('message', gateway.respond.bind(gateway));
}
ワーカーはメッセージを解析し、それを使用して HTTP 要求を作成し、クラスターsend
API を使用してgateway
(上記のコードの最後のブロック) に応答します。
問題
システムに負荷がかかると、奇妙で予測不可能な遅延パターンが発生します。すべての CPU/メモリ/ネットワークの測定値は正常であり、インフラストラクチャのボトルネックを示していません。
質問
ご覧のとおり、特定のワーカーの実際のスループットに関係なく、作業はワーカー間で均等に分散されます。私の推測では、これがレイテンシ スパイクの原因であるということです。おそらく、どこかで個々のワーカーがバックアップされているのでしょう。
これを原理的に、または経験的に確認する方法はありますか? おそらくそれは希望的観測にすぎませんが、このアプローチは単純に平均化されるべきであり、worker-pull 型のアルゴリズムは必要ないように思われます。(解析が完了した後、HTTP 応答を受信した後、ゲートウェイに応答を送信した後など、ワーカーが解放されたと見なすのに最適な時期を判断できないため、これは特に難しいようです。)
私は CPU スケジューリングについて十分に理解していないので、私が赤ニシンを追いかけているのか、それともこれが間違いなく問題を引き起こしている貧弱なアルゴリズムなのかを知ることができません。(もしそうなら、それを改善する方法についてのアイデアは大歓迎です。)