深入位元組版atop: 線上系統的效能監控實踐
背景
atop 是一款開源的單機效能監測工具,支援實時觀測的同時、也支援讀取歷史檔案排查問題。另外一個優點是除提供 CPU、MEM、DISK 等全域性指標外,還提供程序、執行緒級別的各項指標監控資料。鑑於 atop 的這些優點,位元組跳動基於社群的 atop 進行優化,目前已迭代 3 個版本,穩定執行接近三年。本文將和大家分享位元組跳動內部 atop 工具的新特性及使用情況。
傳統特性介紹
What - atop 是什麼
atop 本身是一個單機效能監測工具,每間隔 interval(實時監控預設間隔是 10s,而後臺採集社群預設間隔是 600s,即 10min)時間去採集本機常用的全域性指標和程序指標。直接執行 atop
即可展示,大致分為上下兩部分,分別展示全域性指標和程序指標。同時支援快捷鍵切換多種“介面模式”,用於專門檢視程序的 CPU、記憶體、磁碟等指標資訊。
直觀展示
執行方式
根據使用者使用需求,能夠以多種形式執行。一種是直接執行 atop 二進位制,顯示實時資料;一種是以服務形式(systemd 或 SysV Init)部署在物理機、虛擬機器或容器裡,作為常駐程序,採集資料寫入磁碟,以天為分割單位計入不同檔案;一種是使用 atop -r $atop_log_file
按需讀取歷史資料。是一款少見的能夠支援檢視詳細歷史記錄的工具,這在定位非實時問題時尤其有幫助。
程式碼結構
When - 什麼時候使用 atop
atop 記錄了很多指標,如全域性的 CPU、CPL、MEM、DISK、NET、PSI,程序的 PID、PPID、TID、CMD、SYSCPU、USRCPU、CPUNR、RSIZE、PSIZE、RDDSK、WRDSK 等,稱得上一個大而全的工具。而 atop 本身佔有資源很少,並不會帶來額外的效能開銷。因此很多場景都可以使用 atop 來檢視各種指標,進而幫助使用者更好的瞭解業務程序在作業系統中的呈現。舉例如下:
叢集
目前上游還不支援 atop 指標在叢集粒度的聚合,但位元組內部提供 JSON 資料的輸出,可通過資料處理一系列流程將隸屬同一叢集的所有機器的 atop 資料都入庫儲存(可選擇性按時間對資料進行稀釋)。並按照業務需求加以展示,如分別對全域性常用指標和某類業務(多程序 PID 加以聚合)各項指標繪製成曲線圖,用於觀測 24h 時間週期內的資料變化;也可以用於統計基礎服務的利用率。
單機
線上排查
業務高峰期,如果發現抖動,可直接執行 atop
綜合檢視全域性指標和程序指標的哪項指標異常,進而定位排查問題。一般來說先觀察全域性指標來縮小範圍,看是 CPU、MEM、磁碟讀寫、網路中的哪項引發的問題。常見問題有,如果總 CPU 的 sys 態及 user 態飆高、並且只有幾個單 CPU 核很高,多半是綁核不均勻引起的;如果 CPL(CPU Load Average)不高但 CPU 的中斷 irq 很高,多半是 IO 操作引發的。
歷史定位
前文提到過,常用的監控工具中,能夠提供詳細歷史資料並且能高效儲存的幾乎沒有;如果需要儲存,需要人工干預、打通整個流程。而 atop 本身提供了日誌儲存功能,並自帶日誌壓縮機制,儘量確保儲存無壓力。為保證歷史日誌不會將系統盤打滿,位元組開發了定製化儲存位置和儲存天數的功能,將在下文詳細說明。
功能上線
atop 有個 interval 引數,可通過配置,來定製化資料採集的間隔,如 10s、甚至 1s。如果業務有新功能上線,想自測新功能對系統帶來的影響,可以將 interval 設定成 1 秒,實時觀測各指標的動態變化。
效能優化
atop 提供細粒度的程序態各項指標值的展示,在業務調優過程中,可參考程序態的資料變化來衡量調優是否符合預期。
告警輔助
atop 的資料比較全,有很多其他監控工具不具備的指標,如 oom-kill、per NUMA 指標等。可用於告警資料來源的補充。
How - 如何使用 atop
atop 針對全域性指標和程序指標分別提供了很多快捷鍵,供使用者檢視更多的指標。 接下來列舉一些常見問題,詳細引數可以通過
man atop
進行檢視。
如何使用 atop?如何檢視歷史資料?
使用者可直接執行 atop 命令檢視實時的資訊,也可以通過 atop -r /var/log/atop/atop_$date 檔案檢視歷史資訊。讀取檔案時有多種互動方式,比如-b 代表從什麼時刻開始讀,-e 代表讀取到什麼時刻(在社群支援分鐘級別讀取的基礎上,位元組內部支援秒級別讀取)。快捷鍵說明如下圖:
快捷鍵 | 說明 |
---|---|
b | 輸入時間,格式為"12:23"(時:分) |
t | 前進 10s |
T | 後退 10s |
g | 按 CPU 使用率排序,預設排序方式 |
m | 按記憶體使用率降序排列 |
d | 按磁碟使用率降序排列 |
y | 檢視執行緒資訊 |
j | 檢視 container 聚合資訊 |
c | 檢視詳細的 command line |
l | 定製化檢視每個 CPU 核/每個磁碟/每個網絡卡的資訊 |
f | 展示全域性指標中 fixed 的指標 |
Q | 根據程序狀態過濾,如 R|S|D|Z 等 |
I | 按照 PID 進行搜尋(注:大寫的 i) |
非 root 使用者是否可以檢視日誌?
可以,預設有讀許可權。但是安裝包、重啟服務、修改日誌儲存天數等還是需要 root 許可權。但 非 root 使用者按 d 無許可權實時檢視程序的磁碟資訊 。這是因為非 root 使用者預設被禁止讀取其他使用者的/proc/$pid/io 檔案,反映到 atop 程式碼裡就是沒有設定相關標誌位,導致無法檢視磁碟。
但檢視歷史檔案資料可以打消這個魔咒,也就是說非 root 使用者可以通過 atop -r /var/log/atop/atop_$date
檢視磁碟相關資料,畢竟 atop 寫日誌時是以 root 使用者在執行。
atop 如何檢視執行緒資訊
預設只有程序資訊展示, 按 y 可檢視執行緒 。如下圖,白色為程序,黃色為該程序的所有執行緒。再次按 y,執行緒展示消失。
netatop:記錄程序態網路指標
程序態網路相關的指標是通過定製化安裝 netatop kernel module 完成的。本質上是通過 netfilter hook 獲取程序資料,額外有個 netatopd daemon 負責資料記錄及壓縮。在資料量比較大的場景,會影響到效能,因此預設不開啟該功能。如果開啟,可以按 n 檢視 per 程序的網路指標。
磁碟常見問題
-
全域性指標中 DSK 行的 busy 代表什麼?
-
busy=io_ms/per_cpu_ms,其中 io_ms 是處理 io 所花費的時間(ms 單位是毫秒),busy 就是 過去 10s 內 io 處理的時間佔單 CPU 時間的比例(其中 io wait 並不真實佔用 CPU 資源,而是處於 sleep 狀態) 。
-
按 d 之後,檢視到程序欄的 DSK 列 很高,表示什麼?
-
DSK 列的數值是個 相對比 ,表示該程序佔當前展示的所有程序之和的比率,是個相對值; 換句話說,該列對於排查是哪個程序導致的 heavy load 並無意義。
-
檢視程序的磁碟利用率, 要看 RDDSK, WRDSK 這兩列絕對值 ,表示所屬程序的讀/寫位元組數。
位元組版新特性一覽
NUMA 聚合
隨著雲原生場景的推進,各雲廠商正嘗試將不同特徵的業務(如優先順序不同、延遲敏感度不同的多個業務)混部在同一臺物理機上,儘量充分地將機器的物理資源利用起來,以提高單機的資源利用率。常見的混部場景有在離線混部,而常用的混部手法是將不同業務繫結不同 NUMA,從物理上達到隔離。那麼檢視 NUMA 粒度而不是整機粒度的 CPU、MEM 等指標則更有意義。基於這迫切的需求,位元組內部實現了 NUMA 的監控粒度,相關程式碼已被社群接收,展示效果如下:
https://github.com/Atoptool/atop/pull/163
-
支援 per NUMA 粒度記憶體相關資訊檢視
例:一臺 4NUMA 的機器,其 NUM(Memory per NUMA)展示如下圖
-
支援檢視 per NUMA 記憶體碎片化,使用百分比展示
例:如上圖 NUM 的 frag 欄位。
-
支援 per NUMA 粒度 CPU 相關指標的聚合
例:一臺 4NUMA,運行了虛擬機器的 arm 機器上,其 NUC(CPU per NUMA)展示如下圖

JSON 格式輸出
前文提到過,目前社群不支援 atop 指標在叢集粒度的聚合;除此之外,atop 作為一個單機工具,如果業務想檢視某臺伺服器的監控,需要申請許可權登入到機器上,這在某些場景下比較受限。因此想到有沒有一種方式,針對擁有某個叢集機器許可權的同學來說,可以直接檢視該叢集內所有機器的 atop 資料,而無需再走工單申請單臺機器許可權,即網頁版 atop。
考慮到資料處理過程中 JSON 資料的強相容性,敲定將 atop 的原始資料以 JSON 資料輸出:支援輸出到終端,以及寫本地 unix domain socket 。針對前者,主要是用於本機的一些資料除錯,也可以與其他元件打通,如資料報警等。針對本地 UDS,atop 作為 server 端,提供一種資料輸出的能力;另外需要引入 client 端、監聽並獲取 atop 資料,同時作為資料來源端、與資料處理打通、將本機 atop 資料流過資料通路落入資料庫,供業務方使用。整體流程如下:

用法如下:
Currently we support three types of output: 1. atop -O stdio 2. atop -O only 3. atop -O unixsock -w /path/to/file 10 //Make unixsock non-block to make sure this will not block main engine. And if the unix remote server re-launches, atop will re-connect and continue to work. Usage examples: ./atop ./atop -P ALL ./atop -O only // overwrite parseout, show json to stdio only ./atop -O stdio -P ALL // both parseout and json stdio ./atop -O stdio -w atop.log // print to stdio, as well as file ./atop -O unixsock // overwrite parseout, show json to unixsock ./atop -O unixsock -P ALL // both parseout and json unixsock ./atop -O unixsock -w atop.log // write json to unixsock and file And the detail JSON output format is as follows: { "ip": "a.b.c.d", "timestamp": 1565256314, "CPU": { "hertz": 100, ... "cpu_nums": 40 }, "cpu": [ { "hertz": 100, ... "cpu_id": 0 }, ... { "hertz": 100, ... "cpu_id": 39 } ], ... "PRC": [ { "pid": 1, "p_name": "(systemd)" }, ... { "pid": 73, "p_name": "(migration/12)" } ] }
互動介面改進
雖然 atop 的指標很全,且有歷史記錄可以查詢,但依舊有不少聲音提到 atop 做的還有欠缺。比如無法將所有 CPU 的使用情況同時展示,即使將顯示器橫過來也不能解決,這在高達 128 核的物理機上尤其頭痛。為解決這個痛點,參考類似 htop 的展示方式,結合 atop 本身程式碼,從零開始用 ncurses 加以繪製,展示效果如下。目前只支援 CPU 和 MEM 的展示,如有其他需求,歡迎聯絡我們。
支援類似 htop 直觀的展示所有 CPU 和記憶體的使用情況,但新增 NUMA 粒度的支援。一是解決因 CPU 核數太多展示不全的問題;進一步可以縱覽所有 CPU 的負載,直觀判斷綁核是否有問題
-
雙 NUMA 使用 bar 展示

-
雙 NUMA 使用百分比展示

//注:上面兩張圖為壓測場景
user態:stress -c 20
sys態:iperf -s -i 1 && iperf -c $ip -i 6 -t 600
//numactl -H的結果如下

-
4NUMA 使用 bar 展示

-
4NUMA 使用百分比展示

日誌相關
前面提到,atop 支援歷史日誌的記錄,這在定位排查非實時問題時非常有幫助。然而在位元組內部,曾因 atop 日誌過大引發過比較嚴重的問題。起因是 atop 預設會將日誌寫到/var/log/atop 目錄下,並且記錄所有的程序、執行緒資訊到日誌裡。有些業務伺服器(如 Java 業務)動輒每 10 秒幾萬個執行緒,一天的日誌量高達幾 G,7 天高達幾十 G,如果伺服器本身的系統盤儲存空間很緊張,就會造成系統盤打滿、登入不上機器的嚴重後果。
為解決日誌相關的問題,位元組內部在新版本中推出了以下特性:
-
預設只儲存每個程序的 top100 執行緒
根據日常排查問題來看,一般只關心 topM 的程序或每個程序的 topN 執行緒。觀察每個程序,通常超過 top100 執行緒的 CPU 或 MEM 都處於不活躍狀態,對於排查問題來說意義不大,沒必要記錄到日誌。據此位元組內部引入-H 引數,通過指定-H 100 可以過濾掉 top100(按照 CPU/MEM/DISK 比例之和倒敘排列)之外的執行緒,大大減少了日誌儲存量,尤其適用於執行緒數目多達幾千或幾萬的 Java 業務場景。
-
使用 systemd timer 控制 daily 日誌重定位
引用上游最新的 atop-rotate.timer 和 atop-rotate.service,取代之前的 cronjob。避免某些機器修改時區後未重啟 cron.service,導致 cron 服務重啟時間未遵守本機時間,寫 atop 日誌時間出錯。
-
支援使用者修改 atop 日誌儲存時間,預設儲存為最近 7 天
上游預設儲存天數為 30 天,在實際排查問題時必要性不大,反而浪費了系統盤的儲存空間。如有需要,可以通過 atop-json 機制將本機日誌傳輸到統一的儲存池子中,採取資料稀釋的方式(如保留 topM 程序、按時間順序增大記錄間隔等)進行儲存。位元組內部在 atoprc 中引入 generations
變數,表示儲存天數為 generations+2
天。
例: echo 'generations 1' >> /etc/atoprc && systemctl restart atop
代表只保留儲存最近 3 天的日誌
-
支援使用者修改 atop 日誌儲存位置,預設是/var/log/atop
有些伺服器雖然系統盤儲存空間小,但資料盤有多塊,容量高達幾 T,針對這種場景,使用者可以通過修改 atop 日誌儲存位置,來緩解儲存壓力。位元組內部在 atoprc 中引入 logpath 變數,標識日誌儲存目錄。
例: echo 'logpath /data00/log/atop' >> /etc/atoprc && systemctl restart atop
將日誌儲存到 /data00/log/atop
目錄下
-
限制 atop 日誌儲存總量為 10G,超過 10G 會按照時間倒序刪除日誌檔案
-
解決因 systemd 沒能 daily 重啟 atop 服務,導致持續寫相同檔案,導致單個檔案過大的問題
其他指標及特性
-
通過-b/-e 引數指定時間範圍時支援精確到秒
-
新增 compact_stall、allocastall、InCsumErrors 等指標
-
關閉 perfevent 採集 instr 和 cycle 兩項指標的功能,釋放 PMU 給其它專用工具,如 perf
-
修復低於 4.19 核心,使用者態讀取/proc/$pid/cpuset 檔案遇到 css offline、導致永久陷入核心態的問題
-
修復/run/pacct_source 檔案過大,導致 tmpfs 被佔滿的問題
落地使用情況
到目前為止,位元組已穩定執行接近三年,覆蓋公司全量伺服器,推出 3 個版本。
位元組內部目前在用程式碼已 push 到相關分支,歡迎使用:
-
https://github.com/bytedance/atop/commits/bytedance-internal-v2.6.0%2Bbyted2
相關 repo 請訪問:
-
https://github.com/bytedance/atop
其中 master 分支緊跟社群 atop 的 master 分支,其餘分支是一些已推社群但尚未被合入的特性或 bug fix(如 Fix atop stuck when reading offline css 雖然本質上是核心的 bug,但可以通過修改 atop 程式碼加以規避,避免重啟伺服器)。
合作與共建
新版本 atop 的部分特性已經推社群並被上游接收,接下來還會將其餘特性繼續推上游,更好的回饋社群。
關於位元組跳動系統部 STE 團隊:
位元組跳動系統部 STE 團隊 (STE=System Technologies & Engineering,系統技術與工程) 一直致力於作業系統核心與虛擬化、系統基礎軟體與基礎庫的構建和效能優化、超大規模資料中心的系統穩定性和可靠性建設、新硬體與軟體的協同設計等基礎技術領域的研發與工程化落地,具備全面的基礎軟體工程能力,為位元組上層業務保駕護航。同時,團隊積極關注社群技術動向,擁抱開源和標準。
更多招聘資訊,可郵件聯絡 [email protected] 獲取。
- 位元組跳動自研高效能微服務框架 Kitex 的演進之旅
- 因果推斷在遊戲個性化數值中的實踐及應用
- 位元組跳動自研高效能微服務框架 Kitex 的演進之旅
- OOP 思想在 TCC/APIX/GORM 原始碼中的應用
- 一文了解位元組跳動如何解決資料 SLA 治理難題
- LL-DASH CMAF 低延遲直播
- 深入理解 OC/C 閉包
- 廣告素材優選演算法在內容營銷中的應用實踐
- ByteDoc 3.0:MongoDB 雲原生實踐
- 深入剖析 split locks,i 可能導致的災難
- 抖音 Android 包體積優化探索:資源二進位制格式的極致精簡
- 分析 Android 耗電原理後,飛書是這樣做耗電治理的
- 抖音 Android 效能優化系列:Java OOM 優化之 NativeBitmap 方案
- iOS StoreKit 2 新特性解析
- 抖音 Android 包體積優化探索:資源二進位制格式的極致精簡
- iOS StoreKit 2 新特性解析
- ByteDoc 3.0:MongoDB 雲原生實踐
- 世界編碼器大賽結果公佈,火山引擎獲四項冠軍
- 分析 Android 耗電原理後,飛書是這樣做耗電治理的
- 打造 Go 語言最快的排序演算法