大津です。 これは http.Agent に関する非常に良い課題だと思います。
# 本当は XXXX の YYYY を見てくださいと言いたいところなんですけど、それは 今後の楽しみにしていただけるとありがたいです。 > nodeに興味が出て、勉強のprogramを書いてるところです。 > javascript自体、ecma > scriptの仕様書を見ながら書いているレベルなので、node自体の使い方の質問では無く、javascriptの質問になっているかもしれませんが、その際は指摘していただければと思います。 いえJSの問題ではなく Node.js 固有の原因によるものですので安心してください。 > 書いているのは、httpへの負荷をかけるツールです。 > 書いたcodeを質問用に簡略化したのが、 (中略) > のようなwarningが出ます。 まず Node.js のHTTPクライアントの動作について少し解説が必要かなと思います。 Node では、通常 http.request() で生成したリクエストオブジェクト(req)が HTTPサーバに接続する際、リクエストオブジェクトが直接 HTTPサーバにソケッ ト接続するのではなく、http.Agent が替りにソケット接続を行い、ソケットと リクエストを結びつける管理する役割を担います。 ソケットの最大同時接続数は http.Agent.maxSockets の値が上限で、それを超 えるとリクエストは queue に溜まります。 Agent は接続したソケットをHTTPリクエストに割り当て、HTTPリクエストが終了 すると Agent は既存のソケットを使いまわして他のリクエストに再度割り当て ます。(HTTP keep-alive が有効になっていることが前提です。) リクエストの際、特に Agent の指定をしなればデフォルトで globalAgent が利 用され、最大同時接続数は5つに制限されています。(管理単位は host+port+sourceIP) 上記の知識を前提として以下に回答を書いてみます。 > 疑問なのが > 1. > 51行目で、走ると思われる並列数分setMaxListeners()しているのに、それ以上のlistenerを追加しようとしているのはなぜ? 'socket' イベントで渡される socket オブジェクトはデフォルト(globalAgent 利用時)では5つです。毎回 golbalAgent がリクエストに socket を割り当てる 度にその5つに対してリスナ追加をするので setMaxListners() 値を超えてし まっています。 > 2. > そもそも、http接続毎に生成されるhttp.ClientRequest用のsocketのconnect > eventを、once()でつかまえようとしているのに、複数回のlistener登録が行なわれるのはなぜ? > globalAgent 利用時 socket は 'connect' イベントは最初に接続した5回分しか emit しません。(途中で接続が他の理由で切れない前提ですけど) なのでいくら once でリスナ登録しても emit されないのでリスナは次々登録さ れる状況になります。 > 3. > 結局どう書くのがnode流なの? うーん、いろいろやり方があります。100個ぐらいなら一気に http.request() してやればメモリは多少使いますが、 Agent が勝手に接続をしてくれるでしょう。 スケールするよう最大接続数を parallel のカスタムエージェントを作って、レ スポンス終了毎に順次リクエスト追加するやり方場合を下記 gist に置きました。 https://gist.github.com/2781370 コメントとか書いていませんが、今後の参考にしていただけたらと思います。 (gjslint ベースに書式は変えてます。)
