編者按:sysAK(system analyse kit),是龍蜥社區系統運維 SIG 下面的一個開源項目,聚集阿里百萬服務器的多年運維經驗,針對不同的運維需求提供了一系列工具,形成統一的產品進行服務。本文總結了實際工作中 IO 打滿、IO util 高問題的處理經驗,將它梳理成一套理論分析方法並形成 iofsstat 工具,集成到了sysAK 工具集裏。以下將由作者帶大家一道領略 iofsstat 的獨特魅力。
文/李光水:系統運維SIG核心成員、 毛文安:系統運維SIG負責人。
一、 需求背景
經常碰到這樣一類問題:磁盤被打滿,然後 io utils 高,觸發業務監控告警,磁盤使用的是 HDD,出現問題的時候 iops 已經被打到幾百、bps 也已經到了上百 MB/s,然後持續個幾秒鐘結束,然後過個幾十秒又出現,這就造成了業務監控頻繁告警。業務方會苦惱,磁盤被打滿了到底是真實的業務需求量上來了呢?還是有什麼野進程在佔用 IO。比如之前碰到一例線上問題,平常都是正常的,突然某一天發現 IO 高了很多,然後客户想知道是誰把 IO 整高了,後面通過系統的各個命令組合 +ftrace 腳本統計,找到了貢獻最高的進程來自於一個與業務不相關的容器,他會定時啓動,謎一般的做大量的文件拷貝動作。
二、現有工具
在定位問題這類問題的過程中,我們會通過系統的現有工具,定位具體的進程、文件或者容器,然後採取下一步措施解決問題,如停掉進程、容器並查看問題現象是否消失。一般地,如下幾類工具會使用比較頻繁:
·基於內核 diskstats 衍生的工具,如 iostat、sar-類命令的IO統計功能、vmstat-d
——可以宏觀的從整個磁盤角度去統計 io 信息,如統計整盤的 iops、bps
·基於內核 proc/$pid/io 衍生的工具,如 pidstat -d
——可以統計到進程貢獻的總體IO
·基於 Taskstats 衍生的工具,如 iotop
——可以統計到進程貢獻的總體 IO 以及貢獻的 iowait
儘管系統為我們提供了比較豐富的工具,但總有這樣一種感覺:使用已有的命令,儘管知道磁盤的 IO 高了,但不知道是哪個進程貢獻的;知道系統裏面的某個進程貢獻的 IO 高了,但又不確定這裏有多少 IO 是被我關心的磁盤給消費的,也不知道這些 IO 都是在操作什麼文件,總覺得哪哪都差一點兒。所以總結下來,得到如下幾點訴求:
● 在磁盤 IO 被打滿的情況下,希望觀察是哪個進程貢獻了比較多的 IO
● 系統上統計到某個進程貢獻了大量的 IO,希望觀察到這些 IO 最終是被哪個磁盤給消費,或者這些 IO 是在訪問哪個文件,如果這個進程是來自某個容器,希望依然可以獲取訪問的文件以及此進程所在的容器
而本文所介紹的 iofsstat,實現了從進程角度來統計 IO 信息、文件讀寫信息,滿足了之前提到的幾個訴求,可以應用到 io utils 高、io 打滿類問題的定位中。
三、iofsstat 功能介紹
3.1 統計指定磁盤的進程文件 IO
主要統計某進程對某文件貢獻了多少 IO,對用户呈現的指標為進程角度+磁盤角度,磁盤角度這個毋庸置疑是為了能夠看到磁盤的全貌,進程角度,是更細粒度的,可以看到對應的在這個時刻,各進程的貢獻情況(PS:這裏並非進程貢獻的總和要等於磁盤整體的統計,因為統計的原理不一致,這裏可以更多的關注兩個角度之間的關聯性,如在某一時刻,磁盤統計到高了,這個時候可以看到對應的這個時刻的各個進程的貢獻程度),各指標如下:
進程角度:
comm:進程名、pid:進程id、cnt_rd:讀文件次數、bw_rd:讀文件"帶寬"、cnt_wr:寫文件次數、bw_wr :寫文件"帶寬"、inode:文件inode編號、filepath:文件路徑,當在一次採集週期內由於進程訪問文件很快結束情況下,獲取不到文件名則為"-"。
如進程來自某個容器,在文件名後綴會顯示 [containterId:xxxxxx]
磁盤角度:
xxx-stat:r_iops:磁盤總的讀 iops、xxx-stat:w_iops:磁盤總的寫 iops、xxx-stat:r_bps:磁盤總的讀 bps、xxx-stat:w_bps:磁盤總的寫 bps、xxx-stat:wait:磁盤平均 io 延遲、xxx-stat:r_wait:磁盤平均讀 io 延遲、xxx-stat:w_wait:磁盤平均寫 io 延遲、xxx-stat:util%:磁盤 io utils
sysak iofsstat -d vdb1 --fs 1 #間隔1秒統計一次vdb磁盤上的進程讀寫文件情況
2022/01/19 14:13:48
vda-stat: r_iops w_iops r_bps w_bps wait r_wait w_wait util%
0.00 98.00 0.00 91.5MB/s 946.34 0.00 946.34 93.20
comm pid cnt_rd bw_rd cnt_wr bw_wr inode filepath
dd 55937 0 0 1096 137.0MB/s 9226 /home/data/tfatsf
...
顯示結果按照 bw_rd 與 bw_wr 的和做降序排列,如輸出結果較多想只看某進程情況下,可以使用 -p PID 只查看指定進程。
此功能基於 surftrace 開發,surftrace 是在 ftrace 基礎上封裝的一系列工具集,用於 trace 內核信息,當前發行版主要包含 surftrace、surfGuide 兩大工具,後期還將包含 pylcc(python libbpf compile collections)。更多詳情參考可點擊文末 surftrace 項目代碼鏈接查看。
3.1.1 進程、磁盤、文件信息
因為複雜的 IO 軟件棧,從用户態到落盤,IO 經歷了不同的數據結構上的變化,同時經過 fs 和 block 之後,IO 的生產者也可能發生變化,因此在現有的條件下,無法做到不實現內核代碼就可以直接獲取到這些信息,我們所關注的信息仍需要在內核中解析某些數據結構體外加推演來獲取,像獲取文件名、IO 大小、進程信息等,比如我們通過在 block 層解析每個 io request 就可以獲取到相當飽滿的信息:
通過這種方式,首先可以捕捉到所有類別的 IO,也肯定可以獲取 io 對應的文件信息,但是在 buffer io 情況下,需要在內核大動干戈的去輪詢所有的 task 的 files strcut 反推得到實際寫這個文件的進程,而且一旦進程已經關閉了這個文件,將會推導不出進程,因此不可取,另外應儘可能的避開內核 ko,避免後續使用上受限於內核版本問題;因此考慮 fs 層是否存在可用且穩定不會變化的 tracepoint。
實際上滿足功能的需求,只需要獲取進程信息、IO 大小、dev 編號、文件 inode 編號就夠了,而在文件系統層沒有現成的符合這些需求的 tracepoint,因此考慮通過 kprobe_events 去 hook 特定函數;kprobe_events 又繞不開因為不同內核版本,數據結構會不一致,造成輸入到 kprobe_events 的表達式不一致的問題,幸運的是因為 surftrace 已經幫我們解決了這個問題,我們只需要關注 kprobe 之後數據的解析,而無需關注表達式的變化。
3.1.2 如何獲取文件路徑
通過 3.1.1 已經獲取文件 inode 編號,通過 find -inum 指定磁盤的掛載目錄,或者通過 debugfs 方式,獲取到文件名,但這種方式不僅耗時間也可能會耗 io;因為已經獲取到了進程信息,接下來可以在 /proc/$pid/fd 過濾出來屬於指定磁盤下的文件,然後比對文件的 inode 即可獲取文件名,簡單高效,但缺點是當比對文件過程中文件訪問結束被 close 掉了,就獲取不到文件名了,但這種情況一般在有問題的情況下出現概率也很低(一般關注的 IO 打滿問題基本持續時間也都是秒級別)。
3.2 統計指定磁盤的進程IO貢獻
主要統計某進程對某磁盤貢獻了多少 IO,對用户呈現的指標為進程角度+磁盤角度,磁盤角度這個毋庸置疑是為了能夠看到磁盤的全貌,進程角度,是更細粒度的,可以看到對應的在這個時刻,各進程的貢獻情況(PS:這裏並非進程貢獻的總和要等於磁盤整體的統計,因為統計的原理不一致,這裏可以更多的關注兩個角度之間的關聯性,如在某一時刻,磁盤統計到高了,這個時候可以看到對應的這個時刻的各個進程的貢獻程度),各指標如下:
進程角度:
comm:進程名、pid:進程 id、iops_rd:進程貢獻的讀 iops、bps_rd :進程貢獻的讀bps、iops_wr:進程貢獻的寫iops、bps_wr :進程貢獻的寫bps。
磁盤角度:
同 3.1 節磁盤角度。
sysak iofsstat -d vdb 1 #間隔1秒統計一次vdb磁盤上的進程io貢獻情況
2022/01/19 12:04:38
vda-stat: r_iops w_iops r_bps w_bps wait r_wait w_wait util%
0.00 118.00 0.00 104.2MB/s 976.82 0.00 976.82 95.60
comm pid iops_rd bps_rd iops_wr bps_wr
[dd] 98675 1 4.0KB/s 259 32.4MB/s
[kworker/u12:0] 91022 1 4.0KB/s 198 167.5MB/s
[jbd2/vdb1-8] 19510 0 0 1 4.0KB/s
...
顯示結果按照 iops_rd 與 iops_wr 的和做降序排列,如輸出結果較多想只看某進程情況下,可以使用 -p PID 只查看指定進程,假設看到的是 kworker 類進程貢獻的 io 最高,可以進一步通過 3.1 節功能從 fs 角度來查看是哪個進程、哪個文件的 IO 最多。
3.2.1 實現原理
此功能基於 block 的 tracepoint,可獲取到指定磁盤的來自各進程的 IO 詳細信息,然後統計每個進程的 iops、bps 貢獻。
四、性能開銷
iofsstat 本質上是基於 ftrace 的實現,不會引發宕機,可以放心使用,由於使用的 ftrace 基本內核版本穩定,因此對內核版本依賴性也低,性能開銷方面,經過統計純 IO 統計功能(3.2 節)開銷單核 1% 以下,文件 IO 統計功能(3.1節)稍微高一點,0.x%~3.x%,還在優化。
五、代碼開源
iofsstat 代碼將在 3 月中旬開源,敬請期待。
Gitee sysak 代碼倉鏈接:https://gitee.com/anolis/sysak
surftrace 項目代碼鏈接:https://github.com/aliyun/sur...
系統運維 SIG 地址:https://openanolis.cn/sig/sysom
—— 完 ——
加入龍蜥社羣
加入微信羣:添加社區助理-龍蜥社區小龍(微信:openanolis_assis),備註【龍蜥】與你同在;加入釘釘羣:掃描下方釘釘羣二維碼。歡迎開發者/用户加入龍蜥社區(OpenAnolis)交流,共同推進龍蜥社區的發展,一起打造一個活躍的、健康的開源操作系統生態!
關於龍蜥社區
龍蜥社區(OpenAnolis)是由企事業單位、高等院校、科研單位、非營利性組織、個人等在自願、平等、開源、協作的基礎上組成的非盈利性開源社區。龍蜥社區成立於 2020 年 9 月,旨在構建一個開源、中立、開放的Linux 上游發行版社區及創新平台。
龍蜥社區成立的短期目標是開發龍蜥操作系統(Anolis OS)作為 CentOS 停服後的應對方案,構建一個兼容國際 Linux 主流廠商的社區發行版。中長期目標是探索打造一個面向未來的操作系統,建立統一的開源操作系統生態,孵化創新開源項目,繁榮開源生態。
目前,龍蜥OS 8.4已發佈,支持 X86_64 、Arm64、LoongArch 架構,完善適配飛騰、海光、兆芯、鯤鵬、龍芯等芯片,並提供全棧國密支持。
歡迎下載:
https://openanolis.cn/download
加入我們,一起打造面向未來的開源操作系統!
https://openanolis.cn