你所未知的3種Node.js代碼優(yōu)化方式
Node.js 程序的運(yùn)行可能會(huì)受 CPU 或輸入輸出操作的限制而十分緩慢。從 CPU 角度看,程序運(yùn)行緩慢的典型原因之一就是未經(jīng)優(yōu)化的「熱點(diǎn)路徑」(一段經(jīng)常被訪問的代碼)。從輸入輸出角度看,程序運(yùn)行速度的局限可能是受底層操作系統(tǒng)影響,也可能是出于 Node 本身的故障。更或者,一個(gè)運(yùn)行緩慢的程序可能跟 Node 本身沒有任何關(guān)系,問題在于外部資源,比如數(shù)據(jù)庫查詢或是 API 調(diào)用緩慢,未經(jīng)過優(yōu)化處理。
在本文中,我們將重點(diǎn)識別并優(yōu)化代碼庫中會(huì)導(dǎo)致 CPU 繁重運(yùn)行的操作。同時(shí),將探討生產(chǎn)應(yīng)用的配置文件,分析并作出可提高運(yùn)作效率的改動(dòng)。
由于 Node 的單線程性質(zhì),避免繁重的 CPU 負(fù)載對服務(wù)器來說尤為重要。因?yàn)樵?CPU 上消耗的時(shí)間會(huì)占用響應(yīng)其他請求的時(shí)間。如果你注意到自己的應(yīng)用響應(yīng)速度緩慢,而且 CPU 在這個(gè)過程中始終占用率較高,分析你的程序有助于找出瓶頸,并且使程序恢復(fù)快速運(yùn)行的狀態(tài)。
分析應(yīng)用
復(fù)制生產(chǎn)環(huán)境中出現(xiàn)的緩慢程序問題非常難解決,而且十分耗時(shí)。值得慶幸的是,你不需要親自做這些了。你可以在生產(chǎn)服務(wù)器上收集配置文件數(shù)據(jù),然后離線分析。下面讓我們來看一下幾種分析方法。
1、使用內(nèi)核級工具
首先,你可以使用內(nèi)核級工具,比如 DTrace(Solaris, BSD),perf(Linux),或者 XPerf(Windows),從運(yùn)行的進(jìn)程中收集堆棧跟蹤信息,然后生成火焰圖。內(nèi)核級分析對運(yùn)行中的進(jìn)程影響最小。火焰圖是根據(jù)調(diào)用棧生成的支持放大縮小查看的向量圖形。來自 Netflix 公司的 Yunong Xiao 針對 Linux 系統(tǒng)中 perf,發(fā)表過超贊的演講和推文,幫助你加深對該技術(shù)的了解。如果你想在生產(chǎn)程序中保持高吞吐量,可以參考使用這種方法。
2、
2、使用 V8 分析器
另一個(gè)選項(xiàng)是直接使用 V8 分析器。這種方式會(huì)與程序共享進(jìn)程,因此它會(huì)影響程序性能?;谶@個(gè)原因,請只在你遇到此類問題時(shí)運(yùn)行 V8 分析器來捕獲相關(guān)輸出。該方法的好處是:你可以使用 Chrome 的所有分析工具,結(jié)合其輸出結(jié)果(包括火焰圖),對程序進(jìn)行調(diào)查。
請運(yùn)行以下代碼來測試你的程序:
npm install v8-profiler --save
之后,在你的程序中添加以下代碼:
const profiler = require('v8-profiler')
const fs = require('fs')
var profilerRunning = false
function toggleProfiling () {
if (profilerRunning) {
const profile = profiler.stopProfiling()
console.log('stopped profiling')
profile.export()
.pipe(fs.createWriteStream('./myapp-'+Date.now()+'.cpuprofile'))
.once('error', profiler.deleteAllProfiles)
.once('finish', profiler.deleteAllProfiles)
profilerRunning = false
return
}
profiler.startProfiling()
profilerRunning = true
console.log('started profiling')
}
process.on('SIGUSR2', toggleProfiling)
只要你發(fā)送 SIGUSR2 信號到此進(jìn)程,它就會(huì)開始分析。再次發(fā)送一個(gè) SIGUSR2 信號可以停止分析(代碼如下)。
kill -SIGUSR2 [pid]
該進(jìn)程的分析結(jié)果將被寫入到當(dāng)前工作路徑的文件中(請確保該路徑可被寫入)。由于這是一個(gè)可編程接口,你可以隨意觸發(fā)它(使用 web endpoint,IPC,等等)。如果你對程序在何時(shí)變得緩慢有預(yù)感,你可以在任一時(shí)期觸發(fā)該接口。建立自動(dòng)觸發(fā)對避免持續(xù)監(jiān)看程序是非常有用的,但是它要求你對捕獲時(shí)間以及捕獲時(shí)長有預(yù)測性認(rèn)知。
一旦已經(jīng)收集好配置文件數(shù)據(jù),將它加載到Chrome開發(fā)工具中,開始分析吧!

3、使用進(jìn)程管理器
盡管直接使用 V8 分析器是非常有效且可定制的,但是它會(huì)進(jìn)入你的代碼庫,并且會(huì)向項(xiàng)目添加又一項(xiàng)你可能不想要的依賴性條件。一種替代方式就是使用進(jìn)程管理器,它可以在你需要分析時(shí),用各種工具將你的程序包裝起來。一種可選的工具是來自 StrongLoop 的 SLC 命令行工具。
首先,運(yùn)行npm install strongloop –g,然后運(yùn)行以下代碼:
slc start [/path/to/app]
上述代碼會(huì)在進(jìn)程管理器中啟動(dòng)你的程序,你可以按需提取 CPU 分析數(shù)據(jù)。要想驗(yàn)證并獲取應(yīng)用程序 id,請運(yùn)行:
slc ctl
你將得到與下面類似的運(yùn)行結(jié)果:
Service ID: 1
Service Name: my-sluggish-app
Environment variables:
Name Value
NODE_ENV production
Instances:
Version Agent version Debugger version Cluster size Driver metadata
5.0.1 2.0.2 1.0.0 1 N/A
Processes:
ID PID WID Listening Ports Tracking objects? CPU profiling? Tracing? Debugging?
1.1.61022 61022 0
1.1.61023 61023 1 0.0.0.0:3000
定位應(yīng)用的進(jìn)程 id。在此例中,id 為1.1.61023?,F(xiàn)在我們就能在任意時(shí)間開始分析了,運(yùn)行如下代碼即可:
slc ctl cpu-start 1.1.61023
當(dāng)我們覺得已經(jīng)捕獲到了遲滯行為,就可以運(yùn)行以下代碼來停止分析器:
slc ctl cpu-stop 1.1.61023
以下代碼將寫文件至硬盤:
CPU profile written to `node.1.1.61023.cpuprofile`, load into Chrome Dev Tools
好啦,就是這樣。你可以像在 V8 分析器里那樣把文件加載到 Chrome 里面進(jìn)一步分析。
作出正確決定
在本文中,筆者展示了三種在 Node 中捕獲生產(chǎn)環(huán)境下 CPU 使用量的方式。那么,你應(yīng)該選用哪一種呢?下面是一些幫助你縮小決策范圍的想法:
- 我需要分析很長一段時(shí)間:使用內(nèi)核級工具。
- 我想用 Chrome 開發(fā)工具:使用 V8 分析器或者過程管理器。
- 我想捕獲應(yīng)用中的特定行為:使用 V8 分析器。
- 我不想影響到程序性能:使用內(nèi)核級程序
- 我希望我不用挨個(gè)測試文件來獲取程序分析信息:使用過程管理器
以上就是本文的全部內(nèi)容,3種Node.js代碼優(yōu)化方式,希望大家可以熟練掌握。
- 為高負(fù)載網(wǎng)絡(luò)優(yōu)化Nginx和Node.js的方法
- Extjs優(yōu)化(一)刪除冗余代碼提高運(yùn)行速度
- Extjs優(yōu)化(二)Form表單提交通用實(shí)現(xiàn)
- javascript教程:關(guān)于if簡寫語句優(yōu)化的方法
- PHP小技巧之JS和CSS優(yōu)化工具M(jìn)inify的使用方法
- JavaScript也談內(nèi)存優(yōu)化
- JavaScript中對循環(huán)語句的優(yōu)化技巧深入探討
- nodejs的10個(gè)性能優(yōu)化技巧
- 優(yōu)化Node.js Web應(yīng)用運(yùn)行速度的10個(gè)技巧
相關(guān)文章
node.js基于dgram數(shù)據(jù)報(bào)模塊創(chuàng)建UDP服務(wù)器和客戶端操作示例
這篇文章主要介紹了node.js基于dgram數(shù)據(jù)報(bào)模塊創(chuàng)建UDP服務(wù)器和客戶端操作,結(jié)合實(shí)例形式分析了node.js使用dgram數(shù)據(jù)報(bào)模塊創(chuàng)建UDP服務(wù)器和客戶端,以及進(jìn)行UDP廣播、組播相關(guān)操作技巧,需要的朋友可以參考下2020-02-02
剖析Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式
這篇文章主要介紹了Node.js異步編程中的回調(diào)與代碼設(shè)計(jì)模式,雖然大多數(shù)場合回調(diào)編寫時(shí)的長串括號不怎么好看,但Node的異步性能確實(shí)很好,需要的朋友可以參考下2016-02-02
Node升級后vue項(xiàng)目node-sass報(bào)錯(cuò)問題及解決
這篇文章主要介紹了Node升級后vue項(xiàng)目node-sass報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
node.js 使用ejs模板引擎時(shí)后綴換成.html
本文給大家分享一個(gè)nodejs的小技巧,將ejs模板引擎的模板后綴改成.html的使用方法,非常的簡單實(shí)用,這里推薦給大家。2015-04-04
Node.js中module.exports?和exports使用誤區(qū)
本文主要介紹了Node.js中module.exports?和exports使用誤區(qū),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Node發(fā)出HTTP POST請求的方法實(shí)例小結(jié)
這篇文章主要介紹了Node發(fā)出HTTP POST請求的方法,結(jié)合實(shí)例形式總結(jié)分析了三種常用的post請求操作方法,以及相關(guān)庫操作注意事項(xiàng),需要的朋友可以參考下2023-05-05
CentOS 8.2服務(wù)器上安裝最新版Node.js的方法
這篇文章主要介紹了CentOS 8.2服務(wù)器上安裝最新版Node.js的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12

