Nodejs mkdirP 模塊導致CPU佔用高的問題
近期將nodejs項目部署到服務器上並啓動時,發現node進程的cpu佔用率在40%左右,當時表示非常不解,剛啓動的服務並沒有運行什麼需要大量消耗cpu的邏輯,且此時還未有請求發送到服務器端。
鑑於這種情況,只能猜測是某段程序在初始化一些東西的時候異常,所以才導致了這種情況。
經過對代碼的排查後,最終鎖定出爲題的代碼塊如下:
router.use(multer({
dest: config.uploadDir,
limits:{
fileSize : config.fileSizeLimit, //bytes , == 50M
files : 1
},
rename:function(fieldname, filename) {
return uuid.v1() + "_" + filename + "_" + Date.now();
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...');
},
onError: function (error, next) {
winston.error(error);
next(error);
}
}));
初看這段代碼怎麼也不相信它會佔用這麼高的CPU,所以最大的嫌疑就是multer模塊的初始化了,於是進入源碼看看。
multer初始化部分源碼:
var dest;
if (options.dest) {
dest = options.dest;
} else {
dest = os.tmpdir();
}
mkdirp(dest, function(err) { if (err) throw err; });
var rename = options.rename || function(fieldname, filename) {
var random_string = fieldname + filename + Date.now() + Math.random();
return crypto.createHash('md5').update(random_string).digest('hex');
};
這段代碼最有嫌疑的不是mkdirP(創建目標文件夾)就是crypto的md5了,那麼一個一個排除。首先只是註釋掉mkdirP,重啓node,發現cpu基本爲0了,所以能斷定問題出在mkdirP上了。
單憑這句mkdirp(dest, function(err) { if (err) throw err; });也看不出什麼東西,所以還是得繼續進入mkdirP的實現。
mkdirP在創建文件夾的源碼中有這麼一段:
function mkdirP (p, mode, f, made) {
//此處省略幾行
fs.mkdir(p, mode, function (er) {
if (!er) {
made = made || p;
return cb(null, made);
}
switch (er.code) {
case 'ENOENT':
mkdirP(path.dirname(p), mode, function (er, made) {
if (er) cb(er, made);
else mkdirP(p, mode, cb, made);
});
break;
default:
fs.stat(p, function (er2, stat) {
if (er2 || !stat.isDirectory()) cb(er, made)
else cb(null, made);
});
break;
}
});
看到case ‘ENOENT’時就有點端倪了,在創建文件夾失敗後,又調了mkdirP,這樣如果第一次出問題了,那不就不停的嘗試創建了。如果是這樣,那麼肯定是傳入的路徑出了問題。回頭檢查config裏面的路徑時,發現路徑在部署配置的時候斜槓的方向寫反了:
config.path = 'c:\aa\aa';
正確的應該是:
config.path = 'c:\\aa\\aa';
or
config.path = 'c://aa//aa';
幾經周折終於解決了問題,nodejs的路還很長,走,吃飯去……
文章作者:forevercjl
文章原文鏈接:http://blog.csdn.net/ForeverCjl/article/details/45895795
轉載請註明出處。