線上環境 Linux 系統呼叫追蹤

TiDB_Robot發表於2020-09-28

提到如何動態追蹤程式中的系統呼叫,相信大家第一時間都能想到 strace,它的基本用法非常簡單,非常適合用來解決 “為什麼這個軟體無法在這臺機器上執行?” 這類問題。但如果需要分析線上服務 (特別是延遲敏感型)的某些系統呼叫的延遲時,strace 則不那麼合適,因為它引入的開銷會非常大,從效能分析大師 Brendan Gregg 的測試結果得知,被 strace 追蹤的目標程式的執行速度會降低 100 倍以上,這對生產環境來說將是個災難。

那麼是否有比較好用的工具用在生產環境上呢?答案是肯定的,下面將介紹兩款工具的常用命令,方便大家需要時查閱。

Perf

眾所周知,perf 是 Linux 系統下非常強大的效能工具,由 Linux 核心開發人員在不斷演進和優化。除了可以分析 PMU (Performance Monitoring Unit) 硬體事件,核心事件等通用功能外,perf 還提供了其他 “子模組”,比如 sched 分析排程器,timechart 根據負載特徵視覺化系統行為,c2c 分析可能存在的 false sharing (RedHat 在大量 Linux 的應用上,測試過這套 c2c 的開發原型,成功地發現了很多熱點的偽共享快取行問題。)等, 而 trace 則可用於分析系統呼叫,其功能非常強大,並保證了可以接受的開銷—— 執行速度僅放慢 1.36 倍 (dd 作為測試負載) 。我們一起看下幾個常用的場景:

  1. 呼叫 syscall 數量的 top 排行榜

    perf top -F 49 -e raw_syscalls:sys_enter --sort comm,dso --show-nr-samples
    

    從輸出可以看到在取樣期間,kube-apiserver 的呼叫 syscall 的次數最多。

  2. 顯示超過一定延遲的系統呼叫資訊

    perf trace --duration 200
    

    從輸出中可以看到程式名稱、pid ,超過 200 ms 的具體系統呼叫引數和返回值。

  3. 統計某個程式一段時間內系統呼叫的開銷

    perf trace -p $PID  -s
    

從輸出中可以看到各系統呼叫的次數,返回錯誤次數,總延遲,平均延遲等資訊。

  1. 我們也可以進一步分析高延遲的呼叫棧資訊

    perf trace record --call-graph dwarf -p $PID -- sleep 10
    

  2. 對一組任務進行 trace,比如後臺有 2 個 bpf 工具在執行,我們想看下它們系統呼叫使用情況,就可以先將它們新增到 perf_event 這個 cgroup 下,再執行 perf trace:

    mkdir /sys/fs/cgroup/perf_event/bpftools/
    echo 22542 >> /sys/fs/cgroup/perf_event/bpftools/tasks
    echo 20514 >> /sys/fs/cgroup/perf_event/bpftools/tasks
    perf trace -G bpftools -a -- sleep 10
    

perf-trace 的使用就介紹到這裡,更多的用法請參考 man 手冊,從上面可以看到 perf-trace 的功能非常強大,根據 pid 或 tid 就可以進行過濾。但似乎沒有對容器和 K8S 環境進行便捷的支援。不用著急,接下來介紹的這個工具就是針對容器和 K8S 環境的。

Traceloop

對於 Traceloop 大家可能有點陌生,但提到 BCC 想必大家就覺得熟悉了。BCC 的前端是 Python/C++,其所屬 iovisor 下還有一個專案叫 gobpf 是 BCC 的 go binding。而 Traceloop 則是基於 gobpf 庫進行開發的,此專案的主要目標應用場景是容器、K8S 環境。其原理比較簡單,其架構如圖所示:

核心步驟如下:

  1. 利用 bpf helper 獲取 cgroup id,根據 cgroup id 而不是 pid、tid 進行過濾。

  2. 每個 cgroup id 對應一個 bpf tail call,通過這種方式實現對此 cgroup id 對應的 perf ring buffer 進行寫入。

  3. 使用者空間根據 cgroup id 讀取對應的 perf ring buffer。

需要注意的是,當前 cgroup id 的獲取方式是通過 bpf helper:bpf_get_current_cgroup_id 來獲取的,這個 id 是 cgroup v2 才有的。因此只適用於開啟了 cgroup v2 的環境。尚不確定此專案團隊是否有意向通過讀取 nsproxy 資料結構等方式來對 cgroup v1 進行支援,因此在這裡只做簡單介紹。隨著 K8S 1.19 版本開始支援 cgroup v2,期待 cgroup v2 能儘快普及起來。以下使用 Centos 8 4.18 版本核心進行簡單的演示:在 traceloop 退出時 dump 系統呼叫資訊

sudo -E ./traceloop cgroups  --dump-on-exit /sys/fs/cgroup/system.slice/sshd.service

從輸出中可以看到,其輸出和 strace/perf trace 類似,只是針對 cgroup 進行過濾。需要注意的是 Centos 8 沒有像 Ubuntu 將 cgroup v2 掛載到 /sys/fs/cgroup/unified,而是直接掛載到 /sys/fs/cgroup 下,在使用前建議執行 mount -t cgroup2 來確定掛載資訊。

對於 K8S 平臺,該團隊將 traceloop 整合到 Inspektor Gadget 專案中,通過 kubectl 外掛來執行,由於管網給出詳細的 gif 示例,在這裡就不做過多介紹了,對 cgroup v2 有需求的朋友可以試一試。

Benchmark

從 benchmark 結果看,strace 的引起的目標程式效能下降最大,perf trace 次之,traceloop 最小。

總結

strace 依然是解決 “為什麼這個軟體無法在這臺機器上執行?” 相關問題的利器,但對於分析系統呼叫延遲等問題,perf trace 是合適的選擇,其也是基於 BPF 的實現,對於使用 cgroup v2 的容器、K8S 環境,traceloop 會更方便一些。

更多原創文章乾貨分享,請關注公眾號
  • 線上環境 Linux 系統呼叫追蹤
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章