淺談動態跟蹤技術之DTrace
什麼是動態追蹤
舉個簡單例子,一個人正在健身房裡跑步,我們用攝像機偷偷對他進行錄像,事後我們就可以使用錄像對這個人運動過程中的步頻、速度、呼吸節奏等數據進行分析研究,以便為這個人提供更加科學的付費健身諮詢服務(這個人並不知道被錄像了)。仔細想想這不是一個很有價值的事嗎?
對這個例子的整個過程分析,它大致有幾個特點:
1、對健身者是無感知,不影響他當前正在進行的運動(低影響)
2、我們錄像的時機可以隨時開始,隨時結束(低耦合)
3、錄像的對象可以是人,也可以是物體(可移植)
這就是動態追蹤技術(Dynamic Tracing),在計算機領域是一種後現代的高級調試技術,可以幫助開發者在非常短的時間內,回答一些很難的關於軟體系統方面的問題,從而更快速地排查和解決問題,也可以幫助產品決策者實時了解當前產品的線上運行情況。在火箭般飛速發展的移動互聯網時代,APP的用戶規模,業務種類繁多,邏輯越來越複雜,代碼編寫也不再是單一語言。作為開發者、產品決策者正在面臨無法掌控整個系統的巨大壓力,動態追蹤技術實際就能幫助我們實現這種願景。
動態追蹤的原理
動態追蹤技術通常是基於操作系統內核來實現的。操作系統內核其實可以控制整個軟體世界,因為它其實是處於"造物主"這樣的一個地位。它擁有絕對的許可權,同時它可以確保我們針對軟體系統發出的各種"查詢"不會影響到軟體系統本身的正常運行。換句話說,我們的這種查詢必須是足夠安全的,是可以在生產環境上大量使用的。一般是通過探針這樣的機制來發起查詢。我們會在軟體系統的某一個層次,或者某幾個層次上面,安置一些探針(測試人員術語叫打樁,產品人員術語叫埋點),然後我們會自己定義這些探針所關聯的處理程序,當關聯程序不運行時,這些探針在系統中不會產生影響。而這些關聯程序可以通過這些探針實時地向我們反饋信息,幫助解決許多重大問題。
這有點像中醫裡面的針灸,就是說如果我們把軟體系統看成是一個人,我們可以往他的一些穴位上扎一些「針」,那麼這些針頭上面通常會有我們自己定義的一些「感測器」,我們可以自由地採集所需要的那些穴位上的關鍵信息,然後把這些信息匯總起來,產生可靠的病因診斷和可行的治療方案。這裡的追蹤通常涉及兩個緯度。一個是時間緯度,因為這個軟體還一直在運行,它便有一個在時間線上的連續的變化過程。另一個緯度則是空間緯度,因為可能它涉及到多個不同的進程,包含內核進程,而每個進程經常會有自己的內存空間、進程空間,那麼在不同的層次之間,以及在同一層次的內存空間裡面,我可以同時沿縱向和橫向,獲取很多在空間上的寶貴信息。這有點兒像蛛蛛在蛛網上搜索獵物。
DTrace初探
DTrace是動態追蹤技術的鼻祖,它於 21 世紀初誕生於Solaris操作系統,是由原來的Sun Microsystems公司的工程師編寫的,先後被移植到Linux、FreeBSD、NetBSD及Mac OS X等操作系統上。iOS 系統也有,大名鼎鼎的Instrument工具就是基於DTrace實現的,而且更多的功能還在隨著 iOS 系統進行版本迭代。
DTrace工具組件包括提供器和探測器:
1、提供器:由dtrace內核驅動命令及附加在上面的dtrace腳本組成(後綴名.d)。Mac OS X默認就安裝了dtrace工具;腳本使用D語言編寫,也叫d腳本,Mac OS X系統的 /usr/share/examples/DTTk/ 目錄下有很多例子;
2、探測器(即探針):由提供器啟動,可標識所檢測的模塊和函數,其名稱標準格式為提供器:模塊:函數:名稱,每個探針還具有一個唯一的整數標識符。在蘋果開源的xnu內核中可以看到蘋果版的DTrace源碼,打包為內核模塊來收集跟蹤數據,它提供介面通過 dtrace 內核驅動命令訪問內核數據,在內核源碼中很多帶有provider關鍵字都屬於標識某個模塊數據的探針。其定義如下:
D語言
這裡的D語言語法大部分跟C語言非常相似(這就帶來了很好的可移植性),但總體架構是不同的。每個腳本由若干個探針語句組成。它們都符合如下的形式
probe descriptions
/ predicate /
{
action statements
}
斷言 (predicate) 和動作語句 (action statement) 部分都是可選的。
probe descriptions 即探針描述定義了語句匹配什麼類型的探針,結構就是之前提到的提供器:模塊:函數:名稱—provider:module:function:name,所有的部分都可以省略。其中 BEGIN 語句在所有探針開始之前運行,END 語句在腳本退出時候執行。
[語法很簡單,設計很複雜,更詳細的介紹參見。](https://docs.oracle.com/cd/E23824_01/html/E22973/glghi.html#scrolltoc),常用的如下:
當運行 dtrace 工具時,我們傳入的腳本被編譯成位元組碼。接著位元組碼被傳入安插了探針的代碼中(通常是kernel)。在 kernel 中有一個解釋器來運行這些位元組碼。當將靜態探針加入可執行程序 (一個 app 或 framework),它們被作為S_DTRACE_DOF(Dtrace Object Format)部分被加入,並且在程序運行時被載入進kernel。這樣DTrace就知道當前的靜態探針。
DTrace示例
使用dtrace -l可以查看Mac OS X系統上的所有探針,dtrace -l -m 可以查看指定模塊的探針。
注意
1、如果出現錯誤:dtrace: failed to initialize dtrace: DTrace requires additional privileges
可以提升 dtrace 工具的許可權:sudo dtrace -l
2、如果出現錯誤:dtrace: system integrity protection is on, some features will not be available
可以從安全模式關閉csrutil disable
舉個例子,假設需求是要跟蹤系統 malloc 方法的所有分配內存大小,可以設計探針的定義文件 DTraceDemo.probe:
provider DTraceDemo {
probe malloc_log(void *ptr, size_t size);
};
然後,執行下面的命令生成探針的頭文件,後面帶入測試工程中編譯
/*
* 更多dtrace用法,參見sudo dtrace --help
*(其實沒有help參數,習慣而已)
*/
sudo dtrace -h -o DTraceDemo.h -s DTraceDemo.probe
測試代碼如下:
最後,創建自己的腳本 DTraceDemo.d,文件名必須以 .d 後綴結尾,這是 D 腳本的約定結尾。[更多d腳本例子參見。](https://github.com/opendtrace/toolkit.git)
使用 sudo dtrace -s DTraceDemo.d 命令開始 dtrace 測試,接著啟動測試功能得到輸出如下:
結束語
在許多不同的情況下,需要跟蹤應用程序。對於開發人員來說,可以通過跟蹤應用程序來診斷問題,這可能比使用調試器更方便。DTrace 等工具的跟蹤能力更強,可以獲得非常有針對性的豐富的應用程序信息。在 iOS 開發中經常使用的調試工具instruments,其核心數據採集原理即DTrace。
TAG:DemonHunter |