LWN: kernel developer怎樣利用BPF來觀測系統?
The state of system observability with BPF
By Jonathan Corbet, May 1, 2019, LSFMM
題圖: Photo by rawpixel.com from Pexels
譯者評:Gregg真是一位非常有煽動力的老兄啊~
在2019 Linux Storage, Filessytem, and Memory-Management Summit開場有一個主議題就是Brendan Gregg介紹的Linux system BPF應用。他認為,基於BPF的眾多“superpower”加入kernel後,也更加穩定成熟了,這非常令人激動。現在可以開始討論在Linux商用環境裡(production Linux system)如何不修改kernel來利用BFP的能力了。
Gregg首先演示了一個他剛剛寫出來的小工具,能夠發出一個刺耳的高頻聲,並且隨著他在會場裡走來走去而變化頻率。這個小工具就是利用BPF實現的,提取laptop的kernel裡的WiFi資訊,然後據此生成高頻聲音播放出來。隨著他用身體遮擋干擾訊號強度,高頻聲也會隨之變化。如果laptop連線到他的手機的WIFI hotspot,他就能利用這個機制來檢測他的筆記本距離手機的距離。很有意思,雖然這不是一個真正商用應用,但是非常好的展示了BPF怎樣能用來實現一些此前不容易做到的功能。
Gregg在Netflix工作,Netflix一般有150,000臺server同時在執行,因此Netflix就很關心繫統的performance,他們永遠渴求能有更好的監控工具幫忙查出performance問題的來源。不過,好工具的價值不僅僅是幫助performance tuning。
Better bug reports
例如,Netflix正在試著遷移它的server kernel到4.15版本,然後馬上碰到了一個問題。他們有一個log-rotation service(迴圈日誌服務),會一直執行ps來等某個程序退出。這個工作看起來很簡單直觀,但是在新版本Linux kernel上就是會出錯:ps會把一個仍在執行的process也判定為exit了。這個問題就需要仔細調查一下了。
Gregg先祭出了bpftrace工具(很快各大Linux發行版都會包含),滿心期待能看到system call是在哪裡出了問題的。針對性的,他就準備了下面的命令呼叫:
bpftrace -e 't:syscalls:sys_exit_* /comm == "ps"/ \ { @[probe, args->ret > 0 ? 0 : - args->ret] = count(); }'
Gregg在現場演示了很多程式碼,篇幅所限,大多數都不記錄在本文裡了。可以從他的slides(http://www.brendangregg.com/Slides/LSFMM2019_BPF_Observability.pdf)看到完整內容。上述的命令會報出syscall number,而不是syscall name。果然,馬上就看到了新版本kernel下的一個問題,不過最終看來並不是導致ps出錯的罪魁禍首,這條路就走到頭了。
那麼他接著轉換了策略:也許某些system call發生了“successfully failing"(也就是syscall認為看到的異常現象也是應該正常返回的)。然後接著用bpftrace拿到更多資訊,他終於得到了想要的回答:有時候getdents() system call對/proc/會只返回一部分資料(partial result),這樣我們關注的目標程序就拿不到了,service也就誤以為程序退出了。
所以,這裡的問題應該來自/proc filesystem。然後他利用了ftrace等工具,仔細看了一下在出現partial result的時候呼叫到了哪些函式。然後再用回bpftrace來跟蹤了幾個程式碼分支,最後確定是find_ge_pid()提前停止了,正常時應該繼續讀下一個最大PID的。這裡,其實是因為process-ID table實現有了變化。然後時間到了,他得出發來趕飛機參會了。
所以,他其實現在還沒有解決這個問題。應該不難了,畢竟罪魁禍首找到了,後面應該能拿出解決方案了。不過,這些內容已經足夠說明BPF對調查這個問題有多大幫助了。當前這些基於BPF的監控工具,最大的好處就是能夠提供更好的bug report,描述清楚bug的更多資訊。
One-liners
回到正題,Gregg介紹了一下BPF system的architecture(架構)。最底層,是BPF virtual machine。開發者可以寫一些raw BPF程式碼來操作這個虛擬機器,不過非常非常難,不會有人想要真這麼做的。他在會場調查了一下有多少人寫過raw BPF程式碼,看到房間里居然有那麼多人舉手,他表示震驚,也許全世界的raw BPF程式碼專家都坐在了這個房間吧。要想使用高階語言來操作虛擬機器,可以使用LLVM的backend,能夠用一個類C語言的方式來寫BPF program。然後BCC就可以load這些program然後根據C或者python程式碼來決定執行流程。再上一層,就是今天介紹的bpftrace了,它可以用於寫很方便的one-line tool,一行命令搞定豐富功能。例如,我們怎麼知道page cache的readahead帶來多大幫助?它是真的會加速I/O操作呢,還是會導致更多的cache汙染來拖慢系統?現在不用去瞎想了,直接觀測就好。他用bpftrace寫了一個簡單的工具,記錄readahead引入各個page的時間戳,然後再拿時間戳跟真正用到這些page的時間戳做對比。執行他關心的workload之後,可以看到結果是幾乎所有page都在被load到cache之後的32ms內被訪問過,而從來沒有訪問(referenced)過的page非常少。所以,readhead在他的workload裡面,證明是非常有幫助的,也說明他的application如果能配置更大的readahead的話,會執行的更加有效率。
人們可能會對上面這個場景裡page cache的eviction(空間不夠導致page被換出)也關心同樣的performance資料。那麼只要在這些page被換出的時候,檢視這些page的存活時長,就能夠用於評估page cache的size是否合理了。如果那些page已經很長時間沒有被訪問過了,說明page cache可能設定的太大了。不過這個功能他並沒有實現出來,在座的如果誰有興趣試試的話,他非常歡迎發出來給他抄抄。
他的檢測readahead效能的工具其實不是one-liner(一行命令搞定)的,不過一頁ppt也就能寫得下了。說明bpftrace在建立這類小工具的時候,是非常高效的一個平臺。使用者只要提供一個probe(例如kernel的tracepoint),一個可有可無的filter expression(過濾條件),以及一個action(probe觸發的時候採取什麼行動)。相關的語法非常像是awk或者DTrace。
bpftrace工具裡面內建了一個parser,會把命令解析出來,建立相應的BPF program,然後在關注的event觸發時呼叫。perf的ring buffer也被利用來從kernel高速取出大量資料。不過其實大多數資料都是在kernel裡面先經過了分析處理,然後再用BPF maps給傳遞出來。Version 0.90在3月份剛剛release,下一個版本就是0.10很快會發布(很多人抱怨這個release版本號一定要改掉,看起來好像版本回退了一樣)。
BPF everywhere
Gregg正在寫一本書,介紹怎樣利用BPF來進行performance分析的。與此同時他也在試著改進BPF系統,能把目前意識到的缺陷儘量解決。他用superping工具舉了個例子,superping會附著(hook)到packet的send和receive events上,希望獲取到更精確的ping時間點,不要包含scheduling latency(排程延遲)。不過最終他測出來的時間居然比普通的ping測出來的更加長了。最後他發現network stack好多年前已經解決了這個問題,因為timestamp存在packets裡面,根本不需要這樣一個工具。不過superping工具也確實演示出BPF怎樣根據kernel的標頭檔案來逐個structure的追蹤分析。
還有一個挺有用的工具,tcplife,能夠採集TCP connection的各種資訊。這些資訊通常都是用packet cature工具例如wireshark來採集的,不過採集都會造成不少cost。而tcplife能夠直接hook進networking stack來獲取這個connection從開始到結束的全生命週期的資訊。最開始它是利用了kprobe監測tcp_set_state(),證明這個方案很有用之後,4.15 Linux kernel裡面直接加了一個合適位置的tracepoint。tracepoint比kprobe要更加穩定。
不過Linux 4.16版本里面,這個tracepoint被挪到了inet_sock_set_state(),也提取了更多資訊。這時Gregg的tool就不能用了(因為他的程式碼還在用舊的位置)。不過他覺得這也沒關係,哪怕tracepoint經常會有改動,也總比用kprobe要方便的多。不過他提出了一個建議,最好tracepoint能增加一個pointer來供user space工具用。他知道用這個pointer可能是不可靠的,不過還是對工具有一些價值的。
這裡也點出一個更加普適性的要點:kprobe能作為一個很好的試驗tracepoint的方式。利用kprobe實現的工具,很可能會讓大家有興趣實現一個更合適的tracepoint,以及瞭解需要採集什麼樣的資訊。這樣在提交新的tracepoint的kernel patch的時候,能更好的證明它的必要性。
Gregg最終總結,儘管各種BPF工具提供了各種各樣的資訊,絕大多數的performance優化還是依賴圖形化的工具來分析,而不是用command-line tool。不過,BPF在這些領域也更加重要。現在很容易能總結kernel的各個trace資訊,減少採集performance data時的overhead(額外損失)。這些證明kernel community應該繼續這個方向:”BPF all the things"(用BPF實現一切!)
全文完
極度歡迎將文章分享到朋友圈
長按下面二維碼關注:Linux News搬運工,希望每週的深度文章以及開源社群的各種新近言論,能夠讓大家滿意~