編集
色々と考えた結果、最終的に手がかりになりそうなものを見つけました。
Express ライブラリは、現在 Node+OAuth モジュールを使用して複数のアウトバウンド リクエスト (Facebook、Twitter など) を実行している場合、着信リクエストの受け入れに失敗します。コード全体に多くのログを配置することで、これを特定できました。ここで、アウトバウンド リクエストの途中で「begin-request」ログ(後述)がトリガーされないことがわかりました。
Node+OAuth モジュールがいくつかのアウトバウンド リクエストを作成しているときに、API へのインバウンド リクエスト (ブラウザー ウィンドウ経由) がハングし、それらのアウトバウンド OAuth リクエストの 1 つが終了するまで受信されないことを実証できました。
もちろん、私はすでにやった:
require('http').globalAgent.maxSockets = 999;
IRC の提案に従って、追加しました
console.log(require('http').globalAgent.requests);
しかし、これは常に === {} のように見えます。これは、AFAIK で保留中のインバウンド リクエストがないことを意味します。
したがって、node.jsまたはexpressのいずれかが、利用可能なソケットがたくさんあるはずなのに、何らかの理由で、送信リクエストのために受信リクエストをブロックすることを選択していると結論付けざるを得ません...
これを解決する方法についてのヒントはありますか?
Express、Mongoose などを使用して node.js で作成された API を Amazon Cloud にデプロイしましたが、これは 99% の確率で素晴らしく高速に動作します。
ただし、たまに、リクエストが何らかの理由でドロップされたり、無視されたりすることがあります。私は、通常はミリ秒で完了するリクエストがランダムに応答せず、明確な理由がないことについて話している.
症状は、API エンドポイントに接続するときの単純な「ゲートウェイ タイムアウト」です。直前または直後に、同じパラメータを持つ同じクライアントから行われた同一のリクエストは、問題なく機能します。
もちろん、最初に思ったのは「サーバーの過負荷だ!」ということでした。そのため、リクエストや monogoDB などの最適化に多くの時間を費やしました。最終的に、CPU/ディスク/RAM の使用率が全面的に (Node.js サーバーと Mongo サーバーの両方で)非常に低いということになりました。Scout と RightScale を使用してサーバーをリアルタイムで追跡し、100 ミリ秒以上かかる要求やクエリをログに記録します。現在、私のノード サーバーには 5GB の空き RAM、70% の空き CPU (最初のコア上) などがあります。したがって、パフォーマンスの問題ではないことは 99.99% 確信しています。
最後に、必死の試みに戻りました。クライアントからのすべてのリクエストに乱数を付けました。次に、node.js アプリで、リクエストが最初に受信されたときと完了したときに console.log() を実行します。たとえば、私がエクスプレスで使用するミドルウェアは次のとおりです。
var configureAPI = function() {
return function(req, res, next) {
if(req.body.ruid)
console.log(req.body.ruid);
// more middleware stuff...
};
}
server.configure(function(){
server.use(express.bodyParser());
server.use(configureAPI());
server.use(onError);
// ... more config stuff
}
私が見つけたものは私に衝撃を与えました.明らかに、node.jsアプリは問題のリクエストを受け取っていません. Javascript webapp があり、リクエストと共に送信された "ruid" をコンソールに出力します。リクエストが成功すると、対応する「ruid」が node.js コンソールに表示されます。タイムアウトするたびにありません。
編集:詳細なデバッグと情報。
私のアプリサーバーは実際に開始され(そして継続され)、PHPも提供されます(したがって、Apacheなどがインストールされています)。ウェブサイト (PHP) を提供するにはhttp://streamified.meが必要で、API (node.js) を提供するにはhttp://api.streamified.meが必要だったので、httpd.conf ファイルに(streamified.me ではなく) api.streamified.me へのリクエストが、ポート 8888 経由で node.js に送信されるようにします。
RewriteCond %{HTTP_HOST} ^api.streamified.me
RewriteRule ^(.*) http://localhost:8888$1 [P]
そのため、同じ httpd.conf ファイルで RewriteLogLevel 5 をオンにしてから、ローカルホストで単純な PHP+CURL スクリプトを作成して、ランダムな URL で api.streamified.me をヒットします (これにより、node.js が単純なゲートウェイのタイムアウトになるまで、「見つかりませんでした」応答)。ここで、それが発生したことがわかります。書き換えログは、リクエストがアプリサーバーによって確実に受信され、ポート 8888 に転送されたことを示しています...しかし、node.js (または、少なくとも、ミドルウェアの最初の行のコードの最初の行はそれを取得しません...)
私は自分のnode.jsコードを何度も繰り返してきましたが、ブロッキングコードがないことは確かです。たとえあったとしても、どこかで赤いフラグを立てずにリクエストを逃すほど長くスレッドをブロックすることは想像できません。
私は何が欠けていますか?着信ソケットがブロックされる理由はありますか? node.jsアプリを介して外部APIにかなりの数のHTTPリクエストを作成しますが、受信ソケットをブロックしないでください。
もちろん、エラーログを設定しています。プロセスレベルで有効にしました...
process.addListener("uncaughtException", function (err) {
// some logging code
}
および Express レベル (上記の onError ハンドラー)。エラー ログ関数が機能することはわかっています。以前に両方の関数が起動するのを見たことがあるからです。しかし、どちらもリクエストがドロップされた頃に何も報告せず、コンソールにも何も表示されません...
- 高速バージョン: 3.0.0rc5
- Node.js バージョン: 0.8.12
- 標準の Amazon Cloud セットアップ (m1.large インスタンス) で実行されている node.js アプリの 2 つのインスタンス。2 つのロード バランサーの背後にあり、MongoDB の 3 つのレプリカ セット (これも m1.large) に接続しています。