天天看點

軟體測試 | 普羅米修斯 - 初識PromQL

作者:霍格沃茲測試

了解監控資料

之前講過普羅米修斯自己就是一個時序資料庫, 它從 exporter 拉取的資料都會按時間戳儲存到對應的檔案裡,這個時序資料庫預設會儲存 14 天的資料。 而它自己也開發了一套名為 PromQL 的類 SQL 的查詢語言用來從各種次元讓使用者來查詢并計算監控的資料。 我們先來看一下我自己編寫的 exporter 的接口, 看看它向普羅米修斯的主服務傳回的監控資料是什麼樣的。

軟體測試 | 普羅米修斯 - 初識PromQL

其中 # 開頭的是某個或者某些名額的幫助文檔, 而非 # 開頭的每一行表示目前 Exporter 采集到的一個監控樣本。由于我是使用普羅米修斯的 python client 編寫的 exporter, 是以它自帶了 python 的多個監控名額。 而下面的MemoryUsage 和HttpRequests 就是我自己定義的監控名額了。 這其中MemoryUsage 和HttpRequests 是名額名稱, 花括号内的是這個名額的 label, label 是個非常重要的機制, 它把相同的監控名額按自定義的 label 類型進行分類,比如這個監控資料是哪個機器的, 哪個機房的等等。 是編寫 exporter 的人定義上去的, 目的是在後續使用 PromQL 的時候使用者可以用 label 把監控資料進行分類查詢 。 比如使用者想要抓取每台機器上的 CPU Load 資料,分别顯示出來 。 那它就要在查詢 cpu_load15 的時候用 label 進行分組了。 最後面的浮點數值就是監控資料的值了。

了解時間序列

^
 │   . . . . . . . . . . . . . . . . .   . .   node_cpu{cpu="cpu1",mode="idle"}
 │     . . . . . . . . . . . . . . . . . . .   node_cpu{cpu="cpu1",mode="system"}
 │     . . . . . . . . . . . . . . . .   . .  
 v
   <------------------ 時間 ---------------->
           

在時間序列中的每一個點稱為一個樣本(sample),樣本由以下三部分組成:

  • 名額 (metric):名額名稱和描述目前樣本的 label 集合(上面介紹過一個名額都有哪些東西);
  • 時間戳 (timestamp):一個精确到毫秒的時間戳;
  • 樣本值 (value): 一個浮點型資料表示目前樣本的值。

如下圖:

<--------------- metric ---------------------><-timestamp -><-value->
http_request_total{status="200", method="GET"}@1434417560938 => 94355
http_request_total{status="200", method="GET"}@1434417561287 => 94334

http_request_total{status="404", method="GET"}@1434417560938 => 38473
http_request_total{status="404", method="GET"}@1434417561287 => 38544

http_request_total{status="200", method="POST"}@1434417560938 => 4748
http_request_total{status="200", method="POST"}@1434417561287 => 4785
           

名額類型

在普羅米修斯中,有 4 種類型的名額:Counter, Gauge, Histogram 和 Summary

Counter

counter 類型的名額是一個隻增不減的計數器, 我們上面的 http_request_total 還有 cpu 相關的資訊都是屬于 counter 類型的。 一般在定義 Counter 類型名額的名稱時推薦使用_total 作為字尾。 一般 counter 類型的名額都會配合内置函數 rate 或者 irate 來完成名額的計算。比如我想統計某台機器上監控的程序 CPU 的使用率,那麼可以使用這條語句查詢:

rate(process_cpu_seconds_total{kubernetes_io_hostname="xxxxxxxx"}[5m]) 
           

這裡解釋一下這個查詢的含義。這裡主要解釋 3 個地方

  • 一定有人覺得 cpu 使用率的名額定義成一個隻增不減的 counter 類型很奇怪。 之前講 cgroups 的時候曾經說過我們限制 CPU 的手段是限制程式能夠使用的 cpu 的時間。 CPU 是按時間片輪轉規則去執行任務的。 CPU 會把自己的一個 CPU 時間劃分成很多個小片, 每個小片隻運作一個程序任務, 時間到了就會觸發 CPU 上下文切換, cpu 就會去執行下一個任務。 是以限制和計算一個程序的 CPU 使用, 就看這個程序能使用多少 CPU 時間 。 是以在普羅米修斯裡針對 CPU 的使用也就定義成了 counter 類型了, 通過計算出使用 CPU 的時間數字間接的就可以計算出 CPU 的使用率來。
  • 在這個語句的後面有一個 [5m] 意思是查詢最近 5 分鐘的資料, 這時候會傳回最近 5m 内采集到的所有名額。方面後續我們統計最近 5m 内的 CPU 使用率名額
  • rate 是 PromQL 裡内置的函數, 用來統計資料的增長率。 是以通過 rate 函數就可以計算出 CPU 的使用率了。

Gauge

與 Counter 不同,Gauge 類型的名額側重于反應系統的目前狀态。這類名額的樣本資料可增可減。常見名額如:node_memory_MemFree(主機目前空閑的記憶體大小)、node_memory_MemAvailable(可用記憶體大小)都是 Gauge 類型的監控名額。通過 Gauge 名額,使用者可以直接檢視系統的目前狀态。

使用 Histogram 和 Summary 分析資料分布情況

Histogram 和 Summary 我用的不多,是以還是用網絡上一個例子來說吧, 他們主要用于統計和分析樣本的分布情況。 他們類似在性能測試中我們喜歡檢視 TP 99, TP 95, TP 90 這樣的名額。Histogram 和 Summary 都是為了能夠解決這樣問題的存在,通過 Histogram 和 Summary 類型的監控名額,我們可以快速了解監控樣本的分布情況。

例如,名額 prometheus_tsdb_wal_fsync_duration_seconds 的名額類型為 Summary。 它記錄了 Prometheus Server 中 wal_fsync 處理的處理時間,通過通路 Prometheus Server 的/metrics 位址,可以擷取到以下監控樣本資料:

# HELP prometheus_tsdb_wal_fsync_duration_seconds Duration of WAL fsync.
# TYPE prometheus_tsdb_wal_fsync_duration_seconds summary
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.5"} 0.012352463
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.9"} 0.014458005
prometheus_tsdb_wal_fsync_duration_seconds{quantile="0.99"} 0.017316173
prometheus_tsdb_wal_fsync_duration_seconds_sum 2.888716127000002
prometheus_tsdb_wal_fsync_duration_seconds_count 216
           

從上面的樣本中可以得知目前 Prometheus Server 進行 wal_fsync 操作的總次數為 216 次,耗時 2.888716127000002s。其中中位數(quantile=0.5)的耗時為 0.012352463,9 分位數(quantile=0.9)的耗時為 0.014458005s。

在 Prometheus Server 自身傳回的樣本資料中,我們還能找到類型為 Histogram 的監控名額 prometheus_tsdb_compaction_chunk_range_bucket。

# HELP prometheus_tsdb_compaction_chunk_range Final time range of chunks on their first compaction
# TYPE prometheus_tsdb_compaction_chunk_range histogram
prometheus_tsdb_compaction_chunk_range_bucket{le="100"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="6400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="25600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="102400"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="409600"} 0
prometheus_tsdb_compaction_chunk_range_bucket{le="1.6384e+06"} 260
prometheus_tsdb_compaction_chunk_range_bucket{le="6.5536e+06"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="2.62144e+07"} 780
prometheus_tsdb_compaction_chunk_range_bucket{le="+Inf"} 780
prometheus_tsdb_compaction_chunk_range_sum 1.1540798e+09
prometheus_tsdb_compaction_chunk_range_count 780
           

與 Summary 類型的名額相似之處在于 Histogram 類型的樣本同樣會反應目前名額的記錄的總數 (以_count 作為字尾) 以及其值的總量(以_sum 作為字尾)。不同在于 Histogram 名額直接反應了在不同區間内樣本的個數,區間通過标簽 len 進行定義。

同時對于 Histogram 的名額,我們還可以通過 histogram_quantile() 函數計算出其值的分位數。不同在于 Histogram 通過 histogram_quantile 函數是在伺服器端計算的分位數。 而 Sumamry 的分位數則是直接在用戶端計算完成。是以對于分位數的計算而言,Summary 在通過 PromQL 進行查詢時有更好的性能表現,而 Histogram 則會消耗更多的資源。反之對于用戶端而言 Histogram 消耗的資源更少。在選擇這兩種方式時使用者應該按照自己的實際場景進行選擇。

PromQL 的基本文法

我們直接用名額的名稱進行查詢的話,就可以傳回該名額的所有資料了。 比如直接查詢:process_cpu_seconds_total 查詢結果:

process_cpu_seconds_total{GPUName="T4", beta_kubernetes_io_arch="amd64"}  457320.31
           

而如果我們想查詢某個時間段内的資料則可以用 [5m] 這樣的文法進行查詢。比如查詢process_cpu_seconds_total[5m] 結果如下:

process_cpu_seconds_total{GPUName="T4", beta_kubernetes_io_arch="amd64"} 
457290.56 @1636449224.643
457292.18 @1636449239.643
457294.08 @1636449254.643
457295.48 @1636449269.643
457297.15 @1636449284.643
457298.74 @1636449299.643
457300 @1636449314.643
457301.55 @1636449329.643
457302.9 @1636449344.643
457304.77 @1636449359.643
457306.26 @1636449374.643
457307.93 @1636449389.643
457309.26 @1636449404.643
           

除了制定查詢最近 5m 資料這樣的文法外, 還可以使用時間位移查詢。 比如:process_cpu_seconds_total{}[1d] offset 1d offset 是說查詢的資料偏移一天。 在這個例子裡就是在查詢 2 天前到 1 天前的資料。

上面 的例子本來都會傳回很多資料的,因為我目前監控了許多台機器。 為了不占用太多的篇幅,是以我删除了很多内容。我們知道每個名額都會定義很多個 label。 而如果我們在查詢的時候就可以根據 label 進行過濾, 比如我們可以查詢process_cpu_seconds_total{kubernetes_io_hostname="xxxxxxx"} 這樣就隻會查詢出某台機器的名額了

還可以通過更多 PromQL 的内置函數來聚合查詢結果, 比如我查詢avg(process_cpu_seconds_total{}) by (kubernetes_io_hostname) 結果如下:

| |
|:--|
|kubernetes_io_hostname="xxxxxx"} |457320.31 |
|{kubernetes_io_hostname="xxxxxxxxx"} |463029.44 |
|{} |17048.66272727273 |
|{kubernetes_io_hostname="xxxxxxxx"} |951251.4 |
|{kubernetes_io_hostname="xxxxxxxx"} |1021410.33 |
|{kubernetes_io_hostname="xxxxxxx"} |1617941.71 |
           

上面 我們利用了 avg 這個内置函數來計算 名額的平均值, 并且我們利用了 by 關鍵字制定了名額的某一個 label。 意思是我們先把所有的資料按 kubernetes_io_hostname 進行分類。 然後根據每個分類使用 avg 這個方法統計平均值。

搜尋微信公衆号:TestingStudio霍格沃茲的幹貨都很硬核