淘寶n7505軟路由以及N75SL 1600 內存

本篇文章給大傢談談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生成更多負載。

install

npm 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 Profiler

V8 官方已經為大傢考慮到這點了,提供了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