本篇文章給大傢談談n7505軟路由,以及N75SL 1600 內存的知識點,希望對各位有所幫助,不要忘了收藏本站喔。
文章詳情介紹:
對node工程進行壓力測試與性能分析「幹貨」
作者:小黎
轉發鏈接:
https://mp.weixin.qq.com/s/WBe7ZLoqFD9UqNusnv_IDA
在係統上線前,為了看下係統能承受多大的並發和並發下的負載情況,常常會先進行了壹輪壓測。
曾在壹個項目的壓測過程中,發現服務器的cpu飈的的非常高,而tps,接口耗時、服務可用等都是正常的,這就奇了怪了,自己想了半天也沒想出為啥,不得已求助了大佬,大佬說先查看 cpu processor
what?這是啥??雖然聽不懂,但可以查嘛╭(╯^╰)╮,可還沒等我查出來,大佬直接上手,壹頓騷操作,便找出了原因~ 這著實讓自己汗顏啊,內功遠遠不足啊,回來網上找了資料,惡補壹把如何分析node工程中的性能問題。
這里給大傢分享我學習到的各種工具和方法。
樣例項目為了便於演示,寫了個簡單的小例子
// app.js
const crypto = require('crypto')
const Koa = require('koa')
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router.get('/crypto', async(ctx, next) => {
const salt = crypto.randomBytes(128).toString('base64')
const hash = crypto.pbkdf2Sync('crypto', salt, 10000, 64, 'sha512').toString('hex')
ctx.body = { hash: hash }
console.log(hash)
ctx.status = 200
next()
});
let reqNum = 0
router.get('/empty', async(ctx, next) => {
ctx.body = { hash: 'empty' }
reqNum++;
ctx.status = 200
next()
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log("listen 3000")
})
基於koa2,有兩個路由,壹個/crypto,其中的業務邏輯是,使用crypto庫對字符串加密;壹個是 /empty,沒有業務邏輯的接口,就是個空接口
壓力測試壓力測試工具市麵上有很多種,就不壹壹列舉了,在社區看到有人推薦 autocannon ,就對這個工具做個介紹,官方的簡介是 fast HTTP/1.1 benchmarking tool written in Node.js ,使用node編寫的壓測工具,能比wrk生成更多負載。
installnpm i autocannon -gnpm i autocannon --save
use提供兩種使用方式
命令行 autocannon -c 100 -d 5 -p 2 http://127.0.0.1:3000/test 簡單快速
api調用 autocannon(opts[, cb]) 便於編寫腳本
關鍵參數有這麽幾個
-c/--connections NUM 並發連接的數量,默認10
-p/--pipelining NUM 每個連接的流水線請求請求數。默認1
-d/--duration SEC 執行的時間,單位秒
-m/--method METHOD 請求類型 默認GET
-b/--body BODY 請求報文體
還有很多參數,大傢可以查看官網文檔。
這個庫目前隻能支持壹個接口壓測,我寫了個腳本,可以支持批量壓測和生成測試報告,具體代碼見文末。
report下圖是對 /empty 接口壓測 autocannon -c 100 -d 5 -p 1
http://127.0.0.1:3000/empty 結果如下
autocannon-empty
可看到,每秒有100個鏈接,每個鏈接壹個請求,持續5秒,壹共產生 31k 次請求。報告分三部分,第壹行表示接口的延遲,第二行表示每秒的請求數(tps),第三行表示每秒返回的字節數。那麽,延遲越低,tps越高,就表示接口性能越好,因為empty 是個空接口,所以牠的tps=6221還不錯,響應時間也很快,我們換成 /crypto 接口在試試
autocannon-crypto
立馬看出差距了,這個接口tps衹有77,接口耗時達到了1100ms,說明這個接口有很大的優化空間啊
生成性能文件與分析通過壓測工具我們找到了有問題的接口,那接下來,就要對接口進行剖析了,可是光看接口代碼,不好分析啊,畢竟沒有說服力,我們就需要壹份性能報告,用數據說話,下麵介紹這個兩個方法給大傢
V8 ProfilerV8 官方已經為大傢考慮到這點了,提供了Profiler工具 使用方式也很快捷,步驟如下(以app.js為例)
生成報告在啟動命令中加上 --prof ,如 node --prof app.js ,在項目根目錄會生成isolate-xxxxxxx-v8.log格式的文件,用來記錄運行期間的調用棧和時間等信息,其中內容如下(文件較大,就截取最頂端壹小截)
v8-version,6,1,534,47,0
shared-library,"C:\Program Files\nodejs\node.exe",0x7ff7505f0000,0x7ff751c0f000,0
shared-library,"C:\WINDOWS\SYSTEM32\ntdll.dll",0x7ff8718a0000,0x7ff871a61000,0
shared-library,"C:\WINDOWS\system32\KERNEL32.DLL",0x7ff870590000,0x7ff87063d000,0
shared-library,"C:\WINDOWS\system32\KERNELBASE.dll",0x7ff86e830000,0x7ff86ea18000,0
shared-library,"C:\WINDOWS\system32\WS2_32.dll",0x7ff86ee00000,0x7ff86ee6b000,0
分析報告
對剛剛生成的log文件分析,還是使用官方提供的工具 node --prof-process isolate-xxxxxxxx-v8.log,生成結果如下(去掉無用的部分)
Statistical profiling result from isolate-00000209B99A60A0-v8.log, (17704 ticks, 8 unaccounted, 0 excluded).
[Shared libraries]:
ticks total nonlib name
13795 77.9% C:\WINDOWS\SYSTEM32\ntdll.dll
...
[JavaScript]:
ticks total nonlib name
12 0.1% 11.3% Builtin: CallFunction_ReceiverIsAny
...
[C++]:
ticks total nonlib name
[Summary]:
ticks total nonlib name
94 0.5% 88.7% JavaScript
0 0.0% 0.0% C++
8 0.0% 7.5% GC
17598 99.4% Shared libraries
8 0.0% Unaccounted
[C++ entry points]:
ticks cpp total name
[Bottom up (heavy) profile]:
Note: percentage shows a share of a particular caller in the total
amount of its parent calls.
Callers occupying less than 1.0% are not shown.
ticks parent name
13795 77.9% C:\WINDOWS\SYSTEM32\ntdll.dll
3795 21.4% C:\Program Files\nodejs\node.exe
3768 99.3% C:\Program Files\nodejs\node.exe
3287 87.2% Function: ~pbkdf2 crypto.js:633:16
3287 100.0% Function: ~exports.pbkdf2Sync crypto.js:628:30
3287 100.0% Function: ~router.get D:\github\webapp\js\usen\app.js:8:23
3287 100.0% Function: ~dispatch D:\github\webapp\js\usen\node_modules\@koa-compose\index.js:37:23
...
報告包含六部分:Shared libraries、JavaScript、C++、Summary、C++ entry points 和 Bottom up (heavy) profile,[JavaScript] 部分列出了 JavaScript 代碼執行所占用的 CPU ticks(CPU 時鐘周期),[C++] 部分列出了 C++ 代碼執行所占用的 CPU ticks,[Summary] 列出了各個部分的占比,[Bottom up] 列出了所有 CPU 占用時間從大到小的函數及堆棧信息。
根據 3287 87.2% Function: ~pbkdf2 crypto.js:633:16 可看出這個函數消耗了 87.2% 的cpu
文件的方式不直觀,那我們換個UI界麵的,步驟如下
先clone v8的倉庫下來 git clone https://github.com/v8/v8.git
將日誌文件轉換成 json格式 node --prof-process --preprocess isolate-xxxxxxxxxx-v8.log > v8.json
打開 v8/tools/profview/index.html 文件,是個靜態界麵,在界麵中心選擇剛生成的 v8.json文件,文件解析成功後,界麵如下
v8-ui
具體的功能就不壹壹解釋啦,我們逐層展開,尋找耗時的點,很快便找到耗cpu的地方,如下圖
v8-ui-report
node占比是45%,其中 pbkdf2 crypto.js便占用了92%
v8-profiler除了官方提供之外,我們還可以選擇開源大佬的庫,v8-profiler ,這個庫的創建的時間比較早,6年前便創建了,最近壹次更是在壹年半前,社區評價還是不錯的
生成報告生成方式很簡單,不足的是,需要硬編碼在項目中,如下
profiler.startProfiling('', true);
setTimeout(function() {
var profile = profiler.stopProfiling('');
profile.export()
.pipe(fs.createWriteStream(`cpuprofile-${Date.now()}.cpuprofile`))
.on('finish', () => profile.delete())
}, 1000);
解析報告
Chrome
我們的大Chrome要出馬啦,在Chrome的控制臺,有壹欄 JavaScript Profile 如下圖
chrom-cpu
點擊load,選擇剛剛生成的文件,解析後如下
chrom-report
逐層查看,便了然
flamegraph-火焰圖
使用 flamegraph 生成酷炫的火焰圖,用在報告那是酷炫的壹逼,官網圖如下
flameGraph
使用方式就不細說啦
v8-analytics
這個是社區大佬們,寫的壹個開源庫 v8-analytics,官方介紹如下
解析v8-profiler和heapdump等工具輸出的cpu & heap-memory日誌,可以提供
v8引擎逆優化或者優化失敗的函數標紅展示以及優化失敗原因展示
函數執行時長超過預期標紅展示
當前項目中可疑的內存泄漏點展示
對應的命令如下
va test bailout --only 這個命令可以隻把那些v8引擎逆優化的函數列出來展示。
va test timeout 200 --only 這個命令可以隻把那些指時長超過200ms的函數列出來展示。
va test leak 可以展示出測試的heapsnapshot文件中可疑的內存泄漏點。
這個庫的好處是,省的我們壹個個去點開查找,這樣可以更加便於我們篩選問題啦~
批量壓力測試及生成報告autocannon 隻能運行壹個接口,要想在測試下壹個接口,就得修改代碼,比如想批量測試多個接口,就需要來回改代碼,操作就比較麻煩,所以我基於 autocannon 寫了個腳本,可以逐壹壓測定義好的接口,同時還可以生成測試報告。
// app.jsconst crypto = require('crypto')const Koa = require('koa')const Router = require('koa-router');const app = new Koa();const router = new Router();router.get('/crypto', async(ctx, next) => { const salt = crypto.randomBytes(128).toString('base64') const hash = crypto.pbkdf2Sync('crypto', salt, 10000, 64, 'sha512').toString('hex') ctx.body = { hash: hash } console.log(hash) ctx.status = 200 next()});let reqNum = 0router.get('/empty', async(ctx, next) => { ctx.body = { hash: 'empty' } reqNum++; ctx.status = 200 next()});app.use(router.routes()).use(router.allowedMethods());app.listen(3000, () => { console.log("listen 3000")})
小結
在開發過程中,因為過於隻關註了業務邏輯的實現,壹些可能出現性能的點被忽略掉,而且這些點隻能在量稍微大些的並發場景下才會出現,忘了在哪看到壹句話 可能會出問題的點,便壹定會出問題 性能問題進行分析必不可少。
以上的方法基本上能滿足我們的需求,當然性能涉及的方方麵麵很多比如內存泄漏、事物等,性能調優路漫漫呀, 文章大部分東西都是來自大佬們的總結,我隻是在做壹次整理匯總,便於自己理解與查閱,希望能幫到小夥伴們~
推薦JavaScript學習相關文章《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
《》
作者:小黎
轉發鏈接:
https://mp.weixin.qq.com/s/WBe7ZLoqFD9UqNusnv_IDA