「EMFILE、開いているファイルが多すぎる」問題の解決

こんにちは

404エラーメッセージを別のログファイルに記録することは非常に一般的なことなので、これで問題が生じることはないようです。 少なくとも、私はそう思った。1秒でクライアントが1.5万個の欠落ファイルを要求した。

Node.jsサーバーは「EMFILE、開いているファイルが多すぎます」を呪い、切断しました。

(デバッグモードでは、メインループに陥るエラーを特にキャッチしません)



だから、ファイルへの保存機能は何でしたか:

log: function (filename, text) { //     filename  now() + text var s = utils.digitime() + ' ' + text + '\n'; // utils.digitime() -   -      .. :: fs.open(LOG_PATH + filename, "a", 0x1a4, function (error, file_handle) { if (!error) { fs.write(file_handle, s, null, 'utf8', function (err) { if (err) { console.log(ERR_UTILS_FILE_WRITE + filename + ' ' + err); } fs.close(file_handle, function () { callback(); }); }); } else { console.log(ERR_UTILS_FILE_OPEN + filename + ' ' + error); callback(); } }); }
      
      





まあ、つまり、すべてが直接「額」にあります-開いて、書き留めて、エラーがあればコンソールに出力します。 ただし、前述のように、頻繁に呼び出すと、ファイルを閉じる時間がありません。 たとえばLinuxでは、不快な結果をすべて伴うkern.maxfilesの値に遭遇します。



最も興味深い


解決策として、私は非同期ライブラリを選択しましたが、それなしでは人生は想像できません。

ログ関数自体はモジュールの「プライベート」スコープに移動され、__ logに名前が変更され、わずかに変更されました。コールバックが追加されました。

 __log = function (filename, text) { return function (callback) { var s = utils.digitime() + ' ' + text + '\n'; fs.open(LOG_PATH + filename, "a", 0x1a4, function (error, file_handle) { if (!error) { fs.write(file_handle, s, null, 'utf8', function (err) { if (err) { console.log(ERR_UTILS_FILE_WRITE + filename + ' ' + err); } fs.close(file_handle, function () { callback(); }); }); } else { console.log(ERR_UTILS_FILE_OPEN + filename + ' ' + error); callback(); } }); }; };
      
      







最も重要なこと:プライベートで__writeQueue変数を作成します:

  __writeQueue = async.queue(function (task, callback) { task(callback); }, MAX_OPEN_FILES);
      
      







モジュールの公開部分では、ログは非常にシンプルになりました。

  log: function (filename, text) { __writeQueue.push(__log(filename, text)); },
      
      





それだけですか?!


まさに。 他のモジュールはまだこのf-juを次のように呼んでいます。

 function errorNotFound (req, res) { utils.log(LOG_404, '' + req.method + '\t' + req.url + '\t(' + (accepts) + ')\t requested from ' + utils.getClientAddress(req)); ..
      
      





エラーなし。



メカニズムは単純です。MAX_OPEN_FILES定数を、開いているファイル記述子の最大許容数(たとえば、256)未満の妥当な数に設定します。 さらに、すべての記録試行が並列化されますが、その回数は指定された制限に達するまでです。 新しく到着したものはすべて、前の試行が完了した後にのみキューに入れられ、開始されます(コールバックを追加したことを忘れないでください!これだけです!)。



この記事がこの問題に直面している人々の解決に役立つことを願っています。 または-さらに良い-予防策として機能します。

がんばって。



All Articles