node故障定位頂級技巧動態(tài)追蹤Dynamic?Trace詳解
背景和行文目的
在做 node
或者其他語言的軟件開發(fā)時,是否有以下經(jīng)歷:
- 測試環(huán)境一切正常,發(fā)到生產(chǎn)環(huán)境后,出現(xiàn)詭異問題且難以定位
- 不同機(jī)器、不同容器上,某些邏輯呈現(xiàn)不同的結(jié)果,如時區(qū)、
host
- 對于時好時壞的玄學(xué)問題,束手無策,沒有完整的解決思路,無頭蒼蠅般的各種嘗試,效率低下
- 遇到坑,習(xí)慣搜網(wǎng)友解決方案,然后試很多方案,都不能解決問題,此時就會感覺頭皮發(fā)麻??
我相信,上述我說的經(jīng)歷,大多數(shù)人都會有所共鳴。本文,我將盡可能的把我所學(xué)的動態(tài)追蹤技術(shù)分享給大家。
文章內(nèi)容如下所示:
- 介紹
Dynamic Trace
的概念、優(yōu)勢、原理和用法(我們需要掌握的那部分) - 通過
demo
, 展示Dynamic Trace
技術(shù)的強(qiáng)大 - 實戰(zhàn)演示: 搭建
node
性能監(jiān)控easy-monitor
和構(gòu)建node
應(yīng)用,構(gòu)造詭異故障,并闡述如何用Dynamic Trace
去精確快速定位 - 分享代碼: 會把實戰(zhàn)演示的代碼放到
github
上,大家可以clone
自行去體驗 - 動態(tài)追蹤技術(shù)的未來: 介紹下目前最領(lǐng)先的
Dynamic Trace
方案
總結(jié): 做一個精簡的總結(jié)
附: 其他內(nèi)容
話不多說,直接開整。
動態(tài)追蹤技術(shù)
是什么
這里我把章亦春大佬的原話引用過來:
動態(tài)追蹤技術(shù)其實是一種后現(xiàn)代的高級調(diào)試技術(shù)。它可以幫助軟件工程師以非常低的成本,在非常短的時間內(nèi),回答一些很難的關(guān)于軟件系統(tǒng)方面的問題,從而更快速地排查和解決問題。
優(yōu)勢
優(yōu)勢如下:
- 隨時隨地,按需采集
- 基于操作系統(tǒng)內(nèi)核實現(xiàn),性能損耗極小
原理
動態(tài)追蹤的事件源根據(jù)事件類型不同,主要分為靜態(tài)探針、動態(tài)探針以及硬件事件,其原理如下圖所示:
看不懂也正常,我也看不懂,不過會用進(jìn)行,就跟你不會造車,但你可以把車開的很溜。
簡單點(diǎn)說,就是在 linux
中,進(jìn)程不能直接訪問硬件設(shè)備,當(dāng)進(jìn)程需要訪問硬件設(shè)備時,如 IO
操作,必須由用戶態(tài)切換至內(nèi)核態(tài),然后通過操作系統(tǒng)調(diào)用硬件設(shè)備。 所以可以通過跟蹤進(jìn)程產(chǎn)生的系統(tǒng)調(diào)用,來獲得參數(shù)、返回值、執(zhí)行時間,從而完成動態(tài)追蹤。
我們用的多的是動態(tài)探針,它可以讓我們實時分析線上運(yùn)行的程序。
用法
動態(tài)追蹤工具有 strace
、 dtruss
、 systemtap
、 perf
、 dtrace
、 eBPF
等,我這邊使用的是 strace
和 dtruss
。
也就是 linux
環(huán)境使用 strace
, macos
系統(tǒng)使用 dtruss
。
strace 的主要參數(shù)說明如下表所示:
參數(shù)名 | 含義 |
---|---|
-v | 輸出所有的系統(tǒng)調(diào)用,一些調(diào)用關(guān)于環(huán)境變量、狀態(tài)、輸入輸出等調(diào)用由于使用頻繁,默認(rèn)不輸出 |
-s SIZE | 指定輸出的字符串的最大長度,默認(rèn)為32,文件名一直全部輸出 |
-p PID | 跟蹤指定的進(jìn)程pid |
-c | 統(tǒng)計每一系統(tǒng)調(diào)用的所執(zhí)行的時間,次數(shù)和出錯的次數(shù)等 |
-d | 輸出strace關(guān)于標(biāo)準(zhǔn)錯誤的調(diào)試信息 |
-f | 跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程 |
-o filename | 將strace的輸出寫入文件filename |
-e trace=network | 跟蹤與網(wǎng)絡(luò)有關(guān)的所有系統(tǒng)調(diào)用 |
-e trace=file | 只跟蹤有關(guān)文件操作的系統(tǒng)調(diào)用 |
以上參數(shù)用的最多的就是 -v 、 -s 、 -p 、 -c 。
比如我現(xiàn)在想看部署在 linux
上的 node
應(yīng)用運(yùn)行時的信息,那我就可以執(zhí)行以下命令
strace -p 8000 -v -s 2048
參照參數(shù)說明表解讀上述命令: 跟蹤 pid
為 8000
的進(jìn)程( node
應(yīng)用),輸出所有的運(yùn)行時系統(tǒng)調(diào)用,同時指定字符串最大長度為 2048
。
同理, dtruss
的主要參數(shù)說明如下表所示:
參數(shù)名 | 含義 |
---|---|
-a | 輸出所有詳細(xì)信息 |
-p PID | 跟蹤指定的進(jìn)程pid |
-c | 輸出系統(tǒng)調(diào)用計數(shù) |
-d | 輸出相對時間 |
-e | 輸出運(yùn)行時間 |
-f | 跟蹤由fork調(diào)用所產(chǎn)生的子進(jìn)程 |
-t | 僅檢查此系統(tǒng)調(diào)用 |
-s | 輸出堆棧回溯 |
-o | 輸出cpu時間 |
以上參數(shù)用的最多的就是 -p 、 -c 、 e 、 f 。
注意: 在 macos
系統(tǒng)上使用 dtruss
, 要先執(zhí)行 csrutil disable
命令行例子就不舉了,和 strace
是一樣的道理。
demo 演示
場景: 大家在做開發(fā)的時候,有的會遇到時區(qū)問題,比如說在我的機(jī)器上,時間是對的,但是在其他機(jī)器或者容器上,時間是不對的。然后你就很疑惑,開始搜,找到了所謂的執(zhí)行下某個命令就好了。
思考: 你有沒有想過兩臺機(jī)器的時間為什么不一樣,是哪個環(huán)節(jié)出了問題,比如下面代碼在兩臺機(jī)器上的輸出結(jié)果為什么不同。
console.log(new Date().toLocaleString())
如果你知道動態(tài)追蹤技術(shù),那你就可以開啟 **透視眼 ** , 看看在系統(tǒng)內(nèi)核層面,上面代碼究竟做了什么事情。
動態(tài)追蹤:
參照 dtruss
參數(shù)表,我們執(zhí)行如下命令
sudo dtruss -of node time.js
控制臺如下圖:
輸出了非常多的東西,沒關(guān)系,我們直接搜 toLocaleString
關(guān)鍵詞,結(jié)果如下:
會發(fā)現(xiàn)圖中綠色框中 read(0x14, "console.log(new Date().toLocaleString())\0", 0x28)
出現(xiàn)了搜索的關(guān)鍵詞, 這句表達(dá)式的字面含義是: 系統(tǒng)在讀取 time.js
中的內(nèi)容。
我們順著上面語句往下閱讀,會發(fā)現(xiàn)如下圖所示重要語句:
看到上面三個綠色框內(nèi)容后,已經(jīng)基本確定, new Date().toLocaleString()
返回值, 是系統(tǒng)層面讀取 /etc/localtime
的內(nèi)容。也就是說,這個問題的原因是不同機(jī)器的 /etc/localtime
不一樣
看到這你會明白:
- 為什么不同機(jī)器的返回值會不一樣
- 為什么網(wǎng)上給的時區(qū)解決方案是和
/etc/localtime
有關(guān)的
上面這個小 demo
,可以讓我們更好的感知用 Dynamic Trace
所帶來的巨大好處,所有的代碼在內(nèi)核層面都是裸奔的,它可以幫你更好的定位稀奇古怪的問題。
實戰(zhàn)演示
為了更方便的演示,我這邊所有操作都是在 mac
電腦進(jìn)行的。 我將做以下操作
- 搭建
easy-monitor
環(huán)境 - 啟動一個
egg
應(yīng)用 - 制造制造問題
- 結(jié)合
easy-monitor
用Dynamic trace
進(jìn)行有序精準(zhǔn)定位 - 實戰(zhàn)總結(jié)
搭建 easy-monitor 環(huán)境
花了 20
分鐘左右,搭建好一個本地 easy-monitor
環(huán)境,項目結(jié)構(gòu)如下圖所示:
在官網(wǎng)文檔的情況下做了一點(diǎn)點(diǎn)優(yōu)化,優(yōu)化如下:
- 將監(jiān)控模塊整合成
monorepo
形式,使用pnpm
管理,上workspace
- 采用
turbo
,快速拉起所有包的開發(fā)模式
搭建好,一鍵啟動開發(fā)環(huán)境,終端如下圖所示:
web
控制臺如下圖所示:
啟動一個 egg 應(yīng)用
這個按照官網(wǎng)文檔創(chuàng)建一個 egg
應(yīng)用, 然后按照下圖所示進(jìn)行配置即可
過程非常簡單,在上一個過程,我已經(jīng)用 turbo
一起啟動 egg
應(yīng)用了。
制造問題
簡單化, 我們寫一個 node
服務(wù), 加一個 bug
代碼。代碼如下:
const Controller = require('egg').Controller; const fs = require('fs'); async function read() { const data = await fs.readFileSync(__dirname + '/home.js', 'utf-8'); if (data) read(); } class CpuController extends Controller { async index() { const { ctx } = this; ctx.body = 'cpu will be 90%'; read(); } } module.exports = CpuController;
訪問路由 /cpu
的時候, node
服務(wù)進(jìn)行讀取 home.js
文件死循環(huán)狀態(tài)。 此時 觀察 easy-monitor
cpu
狀態(tài)。如下圖所示:
會發(fā)現(xiàn), cpu
在逐漸升高,然后開始報警,遇到這種問題,如何快速精準(zhǔn)定位呢?
Dynamic trace 精準(zhǔn)定位
在 easy-monitor
上發(fā)現(xiàn) cpu
持續(xù)升高,居高不下時。心里有一個基調(diào),那就是線上可能出問題了,此時,先冷靜,然后進(jìn)行問題定位,步驟如下
- 確定使
cpu
居高不下的進(jìn)程,這個通過easy-monitor
或者top
命令都可以。 - 拿到進(jìn)程
pid
后,通過下面命令,來動態(tài)追蹤,該進(jìn)程運(yùn)行時信息和熱點(diǎn)函數(shù)。
sudo dtruss -c -p 26514
執(zhí)行 10
秒后,退出,查看輸出內(nèi)容,如下圖所示:
會發(fā)現(xiàn),當(dāng)前服務(wù),其 open
、 read
和 fstat64
調(diào)用次數(shù)非常多,心里大概確定該問題和文件操作有關(guān),然后再細(xì)致的看下輸出內(nèi)容,如下圖所示:
會發(fā)現(xiàn),存在大量的讀取路徑 /Users/godkun/monitor/apps/egg-app/app/controller/home.js
的操作,分析到這,基本可以確定問題的原因之一了,那么后面的事情就非常簡單。
快速查閱該部分代碼,發(fā)現(xiàn)存在隱藏的循序讀取邏輯,遂進(jìn)行優(yōu)化,優(yōu)化后, easy-monitor
的性能監(jiān)控顯示, cpu
立刻下降,且運(yùn)行平穩(wěn)。
實戰(zhàn)總結(jié)
我們構(gòu)造了一個循環(huán)讀取文件導(dǎo)致 node
服務(wù) cpu
居高不下的線上問題,然后結(jié)合 easy-monitor
做性能監(jiān)控, 同時使用動態(tài)追蹤技術(shù)進(jìn)行外科手術(shù)式精準(zhǔn)定位線上問題,最后快速給出解決方案,整個過程有序高效。
可以這么說, 動態(tài)追蹤 + easy-monitor
基本可以解決 node
服務(wù)遇到的所有疑難雜癥。
分享代碼
實戰(zhàn)代碼鏈接: github.com/godkun/dyna…
代碼倉庫主要是將 easy-monitor
和 dynamic-trace
結(jié)合,在本地模擬各種問題場景,來學(xué)習(xí)、理解和掌握。
寫的比較急,目前還沒做 mysql
、 redis
的 docker
化,后面有空會更新上這個功能。
動態(tài)追蹤技術(shù)的未來
傳統(tǒng)工具
目前的動態(tài)追蹤工具,如 dtruss
strace
perf
等,都是誕生時間很久的工具了,在用的過程中,會發(fā)現(xiàn)有大量的無用輸出,會影響定位效率,這算是一個小小的缺點(diǎn)。
潛力工具
在動態(tài)追蹤工具中,有一個叫 eBPF
, 它可以只輸出某一行代碼活某一段代碼和系統(tǒng)交互的信息,可以讓我們迅速定位哪里出了問題,而不是面對一大堆輸出信息,去閱讀、查找、判斷和定位。
未來 + 頂尖
目前動態(tài)追蹤領(lǐng)域,最厲害的工具應(yīng)該是章亦春大佬開發(fā)的 xray
,但目前沒有開源,未來期待春哥開源 xray
,將動態(tài)追蹤能力拉滿,造福廣大程序員們。
總結(jié)
到此,本文即將完成,我們可以把動態(tài)追蹤技術(shù)想象成核磁共振。當(dāng)你的應(yīng)用出現(xiàn)問題的時候,無需停機(jī)、即刻對其做一個掃描,它可以讓你看到應(yīng)用代碼在內(nèi)核層面實時裸奔的畫面。
動態(tài)追蹤是 一種不限于 node
服務(wù),可以定位所有服務(wù)線上故障的頂級技術(shù)。
這里補(bǔ)一個內(nèi)容,就是可能會有讀者問, easy-monitor
和 Dynamic Trace
有什么區(qū)別,為什么不能都用 easy-monitor
?
原因很簡單: easy-monitor
只能到 JavaScript
的級別,而 Dynamic Trace
是直接到最底層,也就是操作系統(tǒng)的層面。所以,我們既需要 easy-monitor
,也更需要 Dynamic Trace
。
以上就是node故障定位頂級技巧動態(tài)追蹤Dynamic Trace詳解的詳細(xì)內(nèi)容,更多關(guān)于node Dynamic Trace故障定位的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
NodeJS 將文件夾按照存放路徑變成一個對應(yīng)的JSON的方法
這篇文章主要介紹了NodeJS 將文件夾按照存放路徑變成一個對應(yīng)的JSON的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10Node.js使用bcrypt-pbkdf實現(xiàn)密碼加密
在這個數(shù)字時代,保護(hù)用戶密碼的重要性不言而喻,作為一名資深的前端開發(fā)工程師和技術(shù)博客作者,今天我將帶你詳細(xì)了解如何在 Node.js 環(huán)境中利用 bcrypt-pbkdf 模塊進(jìn)行密碼的哈希處理,確保你的應(yīng)用安全性得到有效提升,需要的朋友可以參考下2024-05-05Nodejs中解決cluster模塊的多進(jìn)程如何共享數(shù)據(jù)問題
本篇文章主要介紹了Nodejs中解決cluster模塊的多進(jìn)程如何共享數(shù)據(jù)問題,有需要的可以了解一下。2016-11-11nodejs開發(fā)微信小程序?qū)崿F(xiàn)密碼加密
本文給大家分享的是在使用nodejs開發(fā)微信小程序的過程中,實現(xiàn)密碼加密的示例代碼,非常簡單,有需要的小伙伴可以參考下2017-07-07