Prometheus 查詢語言 PromQL 的 CPU 使用率計算方法

CPU 使用率的計算方法

翻了幾篇 Prometheus 的 PromQL 查詢 cpu 使用率的文章,說得都不是特別透,結合一篇英文文章終於搞明白了怎麼計算這個指標。

cpu 模式

一顆 cpu 要通過分時複用的方式運行於不同的模式中,可以類比爲讓不同的人使用 cpu,張三使一會兒,李四使一會兒。這些模式可以用 top 命令查看,包括:

  • us:用戶進程使用cpu的時間
  • sy:內核進程使用cpu的時間
  • ni:用戶進程空間內改變過優先級的進程使用的cpu時間
  • id:空閒(沒人用)的cpu時間
  • wa:等待io的cpu時間
  • hi:硬中斷的cpu時間
  • si:軟中斷的cpu時間
  • st:虛擬機管理程序使用的cpu時間

這些時間加在一起是總的cpu時間,這個時間又是什麼意思呢?

cpu 時間

通過 node-exporter 抓取的指標中cpu相關主要是各個 node_cpu_seconds_total

# HELP node_cpu_seconds_total Seconds the cpus spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 230416.36
node_cpu_seconds_total{cpu="0",mode="iowait"} 3.86
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 1.05
node_cpu_seconds_total{cpu="0",mode="softirq"} 302.24
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 3829.27
node_cpu_seconds_total{cpu="0",mode="user"} 4802.39
node_cpu_seconds_total{cpu="1",mode="idle"} 230389.47
node_cpu_seconds_total{cpu="1",mode="iowait"} 30.73
node_cpu_seconds_total{cpu="1",mode="irq"} 0
node_cpu_seconds_total{cpu="1",mode="nice"} 1.09
node_cpu_seconds_total{cpu="1",mode="softirq"} 486.8
node_cpu_seconds_total{cpu="1",mode="steal"} 0
node_cpu_seconds_total{cpu="1",mode="system"} 3928.86
node_cpu_seconds_total{cpu="1",mode="user"} 4919.87

每個指標就是某一核cpu的某個模式的運行時間,單位是秒。把某一核各個模式的 cpu 時間加起來的秒數就是執行 uptime
得到的系統開機以來運行的總秒數了(/proc/uptime 的第一列,第二列是各核的空閒時間和)。這就理解了爲什麼這些值都是單調遞增的。比如node_cpu_seconds_total{cpu="0",mode="idle"} 230416.36這個值的意思是自系統開機以來到當前時點,cpu0的空閒時間是230416.36秒。用它除以 uptime 就是開機以來 cpu0 的空閒率。加入現在是5點,那你5點過5分再查一下這個值,肯定會大於等於現在這個值。

計算 cpu 使用率的公式分解

下面一步一步推導cpu使用率的計算公式:

  1. cpu0 5分鐘內處於空閒狀態的時間:increase(node_cpu_seconds_total{cpu="0",mode="idle"}[5m]),increase 的意思是表示增量,剛纔說了 node_cpu_seconds_total 是單調遞增的,這個公式的結果是當前時點的 node_cpu_seconds_total 減去5分鐘之前的 node_cpu_seconds_total,也就是這5分鐘之內處於idle 狀態的 cpu 時間。
  2. cpu0 5分鐘內處於空閒狀態的時間佔比:increase(node_cpu_seconds_total{cpu="0",mode="idle"}[5m]) / increase(node_cpu_seconds_total{cpu="0"}[5m]),分母其實就是5分鐘=300秒。
  3. 一臺主機所有 cpu 5分鐘內處於空閒狀態的時間佔比,用 sum() 函數累加各核數值:sum (increase(node_cpu_seconds_total{mode="idle"}[5m])) / sum (increase(node_cpu_seconds_total{mode="idle"}[5m]))
  4. 如果 Prometheus 監控多臺主機,要根據每臺主機做 sum:sum by (instance)(increase(node_cpu_seconds_total{mode="idle"}[5m])) / sum by (instance)(increase(node_cpu_seconds_total[5m]))
  5. cpu 使用率 = 1 - cpu 空閒率:100 * (1 - sum by (instance)(increase(node_cpu_seconds_total{mode="idle"}[5m])) / sum by (instance)(increase(node_cpu_seconds_total[5m])))

PromQL 有計算比率的函數:rate()irate(),可以簡化計算公式爲:

100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) 

參考連接

irate 和 rate

官方文檔定義 irate() 是基於最後兩個數據點計算一個時序指標在一個範圍內的每秒遞增率。我半天沒想明白最後兩個數據點是哪兩個,怎麼定義的,後來忽然想到它就是你所採集到的最後兩個數據,這個兩個數據點的間隔就是 scrape_interval。如果使用 irate(),只要方括號中查詢的時間段長度大於 scrape_interval,那麼在一個 scrape_interval 之內,查詢不同的時間長度的結果是一樣的。舉個栗子:scrape_interval 設置爲30s,那麼方括號裏面填1m、2m、5m、10m,查詢的結果是不變的,只要前後兩次查詢在30s之內。也就是說查詢的時間範圍至少要大於等於 scrape_interval,以保證這個時間範圍內至少有兩個數據點,大於 scrape_interval 的兩倍比較保險。

rate() 是計算一個時序指標在一個範圍內的每秒平均遞增率,它僅使用第一個和最後一個數據點。如果查詢的時間範圍內僅有兩個數據點,那麼它的查詢結果就等於 irate()。它的圖像更平滑,更適合用於告警。

參考連接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章