深入位元組版atop: 線上系統的效能監控實踐

語言: CN / TW / HK

背景

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] 獲取。