Prometheus 入門學習(一)

一 、設計架構

監控系統的總體架構大多是類似的,都有數據采集、數據處理存儲、告警動作觸發和告警,以及對監控數據的展示。
下面是 Prometheus 的架構:


image.png

Prometheus Server 負責定時從 Prometheus 采集端 Pull(拉) 監控數據。Prometheus 采集端可以是實現了 /metrics 接口的服務,可以是從第三方服務導出監控數據的 exporter,也可以是存放短生命周期服務監控數據的 Pushgateway。相比大多數采用 Push(推) 監控數據的方式,Pull 使得 Promethues Server 與被采集端的耦合度更低,Prometheus Server 更容易實現水平拓展。

對于采集的監控數據,Prometheus Server 使用內置時序數據庫 TSDB 進行存儲。同時也會使用這些監控數據進行告警規則的計算,產生的告警將會通過 Prometheus 另一個獨立的組件 Alertmanager 進行發送。Alertmanager 提供了十分靈活的告警方式,并且支持高可用部署。

對于采集到的監控數據,可以通過 Prometheus 自身提供的 Web UI 進行查詢,也可以使用 Grafana 進行展示。

二、配置 Prometheus

Prometheus 的配置項是整個組件的核心,配置是聲明式的,這點我覺得是蠻棒的,降低使用門檻,如果想熟練的使用 Prometheus,還是需要把配置文檔好好閱讀幾遍,Prometheus 的官方文檔質量還是蠻高的。最基礎的配置如下:

global

定義 Prometheus 拉取監控數據的周期 scrape_interval 和 告警規則的計算周期 evaluation_interval。

rule_files

指定了告警規則的定義文件。

scrape_configs

scrape_configs 是 Prometheus 最為重要的配置之一,指定了 Prometheus 實例如何抓取 metrics
示例:

global:
  # How frequently to scrape targets by default.
  [ scrape_interval: <duration> | default = 1m ]

  # How long until a scrape request times out.
  [ scrape_timeout: <duration> | default = 10s ]

  # How frequently to evaluate rules.
  [ evaluation_interval: <duration> | default = 1m ]

  # The labels to add to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    [ <labelname>: <labelvalue> ... ]

# Rule files specifies a list of globs. Rules and alerts are read from
# all matching files.
rule_files:
  [ - <filepath_glob> ... ]

# A list of scrape configurations.
scrape_configs:
  [ - <scrape_config> ... ]

# Alerting specifies settings related to the Alertmanager.
alerting:
  alert_relabel_configs:
    [ - <relabel_config> ... ]
  alertmanagers:
    [ - <alertmanager_config> ... ]

# Settings related to the remote write feature.
remote_write:
  [ - <remote_write> ... ]

# Settings related to the remote read feature.
remote_read:
  [ - <remote_read> ... ]
scrape_configs
# scrape_configs

# job 是 Prometheus 中最基本的調度單位,一個 job 可能會擁有多個 instances,就像一個服務可能會擁有多個實例一樣。
job_name: <job_name>

# 抓取時間間隔。
[ scrape_interval: <duration> | default = <global_config.scrape_interval> ]

# 抓取超時時間。
[ scrape_timeout: <duration> | default = <global_config.scrape_timeout> ]

# 默認的 web path 是 /metrics,現在對整個社區來說也是一個約定俗成的東西,基本不會有變動。
[ metrics_path: <path> | default = /metrics ]

# 協議格式 http/https?
[ scheme: <scheme> | default = http ]

# 查詢還可以帶參數,但一般也沒這個必要。
params:
  [ <string>: [<string>, ...] ]

# tls 證書配置,不過目前如果使用的服務都是跑在 kubernetes 集群內,且無對外部暴露的話,也不用考慮 tls。
tls_config:
  [ <tls_config> ]

# 代理配置。
[ proxy_url: <string> ]

# 下面的都是服務發現的配置,Prometheus 原生地提供了多種服務發現的方案。
# 這里只簡單介紹 static_sd_config 和 kubernetes_sd_configs 兩種。
# 目的是為了結合服務發現實現 Prometheus 的熱更新,不必再手動地更新配置。
# 使用 prometheus-operator 本質上是與 kubernetes_sd_configs 相結合,只是 operator 幫我們屏蔽了這些復雜性。
# 對于其他服務發現體系的,可以到官網上查看具體的配置項。
# https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config

# kubernetes_sd_configs 實現的思路其實就是通過 Kubernetes REST API 獲取對應的資源的信息。
# 包括 node/service/pod/endpoints/ingress
# kubernetes 會給每種資源注入自己的信息,當然資源本身也可以自定義一些附帶信息,如 labels/annotation 等。
# 獲取到的數據都以 __meta 作為前綴,在 Prometheus 中,雙下劃線為前綴的 metrics 是不會被暴露到外部的。
# 所以可用 relabels 來將 __meta_* metrics 轉換為自己想要的形式。
kubernetes_sd_configs:
  [ - <kubernetes_sd_config> ... ]

# 如果你是單機使用并且沒有任何服務發現體系的話,可以用 static_configs
# <static_config>
# targets:
# targets 就是上面指的一個 job 可能會有多個 instances 的情況,列表類型。
#  [ - '<host>' ]
# Labels assigned to all metrics scraped from the targets.
# labels:
# [ <labelname>: <labelvalue> ... ]
static_configs:
  [ - <static_config> ... ]

# relabel 涉及到幾種 action,action 指的是你可以根據正則捕獲結果對 label 進行何種操作,是丟棄呢,還是改寫呢?
# 具體內容可以參考下面這篇博客
# https://www.li-rui.top/2019/04/16/monitor/Prometheus%E4%B8%ADrelabel_configs%E7%9A%84%E4%BD%BF%E7%94%A8/
# 
# actions 類型如下
# 
# replace       根據正則匹配標簽的值進行替換標簽
# keep          根據正則匹配標簽的值保留數據采集源
# dro           根據正則匹配標簽的值剔除數據采集源
# hashmod       hash 模式
# labelmap      根據正則匹配標簽的名稱進行映射
# labeldrop     根據正則匹配標簽的名稱剔除標簽
# labelkeep     根據正則匹配標簽的名稱保留標簽
relabel_configs:
  [ - <relabel_config> ... ]
alertingRule

采集了 metrics 可以被告警系統使用,所以我們需要根據手上掌握的數據來定義告警規則。首先來看看官方給出的一個基礎示例。:

groups:
- name: example
  rules:
  - alert: HighRequestLatency
    expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5
    for: 10m
    labels:
      severity: page
    annotations:
      summary: High request latency

規則模板如下

# The name of the alert. Must be a valid metric name.
# 告警規則名字。
alert: <string>

# The PromQL expression to evaluate. Every evaluation cycle this is
# evaluated at the current time, and all resultant time series become
# pending/firing alerts.
# promQL 表達式,需要符合 promQL 語法
expr: <string>

# Alerts are considered firing once they have been returned for this long.
# Alerts which have not yet fired for long enough are considered pending.
# 規則匹配的持續時間
[ for: <duration> | default = 0s ]

# Labels to add or overwrite for each alert.
# labels 用于提供附帶信息,在 alertmanagers 中可以用到,可以為 golang 標準模板語法。
labels:
  [ <labelname>: <tmpl_string> ]

# Annotations to add to each alert.
# Annotations 用于提供附帶信息,在 alertmanagers 中可以用到,可以為 golang 標準模板語法。
annotations:
  [ <labelname>: <tmpl_string> ]
recordingRule

Prometheus 提供一種記錄規則(Recording Rule) 來支持后臺計算的方式,可以實現對復雜查詢的 PromQL 語句的性能優化,提高查詢效率。記錄規則的基本思想是,它允許我們基于其他時間序列創建自定義的 meta-time 序列。

在 Prometheus Operator 中已經有了大量此類規則,比如:

groups:
  - name: k8s.rules
    rules:
    - expr: |
        sum(rate(container_cpu_usage_seconds_total{image!="", container!=""}[5m])) by (namespace)
      record: namespace:container_cpu_usage_seconds_total:sum_rate
    - expr: |
        sum(container_memory_usage_bytes{image!="", container!=""}) by (namespace)
      record: namespace:container_memory_usage_bytes:sum

上面的這兩個規則就完全可以執行上面我們的查詢,它們會連續執行并以很小的時間序列將結果存儲起來。

sum(rate(container_cpu_usage_seconds_total{job="kubelet", image!="", container_name!=""}[5m])) by (namespace)

將以預定義的時間間隔進行評估,并存儲為新的指標,新指標與內存查詢相同,效率更高

namespace:container_cpu_usage_seconds_total:sum_rate

同樣的,我們先來看官方給出的基礎示例。

groups:
  - name: example
    rules:
    - record: job:http_inprogress_requests:sum
      expr: sum(http_inprogress_requests) by (job)
rule 規則模板如下

# The name of the time series to output to. Must be a valid metric name.
record: <string>

# The PromQL expression to evaluate. Every evaluation cycle this is
# evaluated at the current time, and the result recorded as a new set of
# time series with the metric name as given by 'record'.
# promQL 表達式,需要符合 promQL 語法
expr: <string>

# Labels to add or overwrite before storing the result.
labels:
  [ <labelname>: <labelvalue> ]

? 當一個 node_exporter 被安裝和運行在被監控的服務器上后
?使用簡單的 curl命令 就可以看到 exporter 幫我們采集到的 metrics 數據,以 key/value 形式展現和保存。curl localhost:9100/metrics:9100 為exporter 默認端口號。

[root@node-3 ~]# curl localhost:9100/metrics | grep node_cpu
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0# HELP node_cpu_guest_seconds_total Seconds the cpus spent in guests (VMs) for each mode.
# TYPE node_cpu_guest_seconds_total counter
node_cpu_guest_seconds_total{cpu="0",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="0",mode="user"} 0
node_cpu_guest_seconds_total{cpu="1",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="1",mode="user"} 0
node_cpu_guest_seconds_total{cpu="10",mode="nice"} 0
node_cpu_guest_seconds_total{cpu="10",mode="user"} 0
node_cpu_guest_seconds_total{cpu="11",mode="nice"} 0

三、使用 Prometheus Web UI

一般的當 Prometheus 啟動之后,可以在瀏覽器輸入 http://localhost:9090 打開 Prometheus Web UI
這里我使用了 Ingress來做代理轉發,并修改本地 Host 實現的。(細節還待研究)

image.png

四、采集數據格式及分類

4.1 采集數據的格式

Prometheus 使用 metric 表示監控度量指標,它由 metric name (度量指標名稱)和 labels (標簽對)組成:

<metric name>{<label name=<label value>, ...}

Exporter 接口數據規范格式如下:

# HELP <監控指標名稱> <監控指標描述>
# TYPE <監控指標名稱> <監控指標類型>
<監控指標名稱>{ <標簽名稱>=<標簽值>,<標簽名稱>=<標簽值>...} <樣本值1> <時間戳>
<監控指標名稱>{ <標簽名稱>=<標簽值>,<標簽名稱>=<標簽值>...} <樣本值2> <時間戳>

*時間戳應為采集數據的時間,是可選項,如果 Exporter 沒有提供時間戳的話,Prometheus Server 會在拉取到樣本數據時將時間戳設置為當前時間;

metric name 指明了監控度量指標的一般特征,比如 http_requests_total 代表收到的 http 請求的總數。metric name 必須由字母、數字、下劃線或者冒號組成。冒號是保留給 recording rules 使用的,不應該被直接使用。

labels 體現了監控度量指標的維度特征,比如 http_requests_total{method=“POST”, status="200“} 代表 POST 響應結果為 200 的請求總數。Prometheus 不僅能很容易地通過增加 label 為一個 metric 增加描述維度,而且還很方便的支持數據查詢時的過濾和聚合,比如需要獲取所有響應為 200 的請求的總數時,只需要指定 http_request_total{status=“200”}。

Prometheus 將 metric 隨時間流逝產生的一系列值稱之為 time series(時間序列)。某個確定的時間點的數據被稱為 sample(樣本),它由一個 float64 的浮點值和以毫秒為單位的時間戳組成。

4.2 采集數據的分類

在了解過 Prometheus 采集數據的格式之后,我們來了解一下它的分類。Prometheus 將采集的數據分為 CounterGaugeHistogramSummary 四種類型。

需要注意的是,這只是一種邏輯分類,Prometheus 內部并沒有使用采集的數據的類型信息,而是將它們做為無類型的數據進行處理。這在未來可能會改變。

下面,我們將具體介紹著四種類型。

Counter

Counter 是計數器類型,適合單調遞增的場景,比如請求的總數、完成的任務總數、出現的錯誤總數等。它擁有很好的不相關性,不會因為重啟而重置為 0。

Gauge

Gauge 用來表示可增可減的值,比如 CPU 和內存的使用量、IO 大小等。

Histogram

Histogram 是一種累積直方圖,它通常用來描述監控項的長尾效應。

舉個例子:

假設使用 Hitogram 來分析 API 調用的響應時間,使用數組 [30ms, 100ms, 300ms, 1s, 3s, 5s, 10s] 將響應時間分為 8 個區間。那么每次采集到響應時間,比如 200ms,那么對應的區間 (0, 30ms], (30ms, 100ms], (100ms, 300ms] 的計數都會加 1。最終以響應時間為橫坐標,每個區間的計數值為縱坐標,就能得到 API 調用響應時間的累積直方圖。

Summary

Summary 和 Histogram 類似,它記錄的是監控項的分位數。什么是分位數?舉個例子:假設對于一個 http 請求調用了 100 次,得到 100 個響應時間值。將這 100 個時間響應值按照從小到大的順序排列,那么 0.9 分位數(90% 位置)就代表著第 90 個數。

通過 Histogram 可以近似的計算出百分位數,但是結果并不準確,而 Summary 是在客戶端計算的,比 Histogram 更準確。不過,Summary 計算消耗的資源更多,并且計算的指標不能再獲取平均數或者關聯其他指標,所以它通常獨立使用。

4.3 數據采集流程

target:采集目標,Prometheus Server 會從這些目標設備上采集監控數據
sample: Prometheus Server 從 targets 采集回來的數據樣本
meta label: 執行 relabel 前,target 的原始標簽。可在 Prometheus 的 /targets 頁面或發送 GET /api/v1/targets 請求查看。

image.png

4.3.1 relabel (targets 標簽修改/過濾)

relabel 是 Prometheus 提供的一個針對 target 的功能,relabel 發生 Prometheus Server 從 target 采集數據之前,可以對 target 的標簽進行修改或者使用標簽進行 target 篩選。注意以下幾點:

Prometheus 在 relabel 步驟默認會為 target 新增一個名為 instance 的標簽,并設置成 “address” 標簽的值;(下圖instance標簽值為address標簽值)
在 relabel 結束后,以 “__” 開頭的標簽不會被存儲到磁盤;
meta label 會一直保留在內存中,直到 target 被移除。

image.png
relabel 配置

relabel 的基本配置項:

source_labels: [, …] #需要進行 relabel 操作的 meta labels
target_label: #relabel 操作的目標標簽,當使用 action 為 “replace” 時會把替換的結果寫入 target_label
regex: #正則表達式,用于在 source_labels 的標簽值中提取匹配的內容。默認為"(.*)"
modulus: #用于獲取源標簽值的哈希的模數
replacement: #regex 可能匹配到多個內容,replacement 指定要使用哪一個匹配內容進行替換,默認為 “$1”,表示使用第一個匹配的內容
action: <relabel_action> #定義對 source_labels 進行何種操作,默認為 “replace”

scrape_configs:
??- job_name: prometheus
????relabel_configs:
???? - source_labels: ["__address__"] #我們要替換的 meta label 為"__address__"
?????? target_label: "host" #給 targets 新增一個名為 "host" 的標簽
?????? regex: "(.*):(.*)" #將匹配的內容分為兩部分 groups--> (host):(port)
?????? replacement: $1 #將匹配的 host 第一個內容設置為新標簽的值
?????? action: replace

五 、Recording rules案例分析

recording rules作用
recording rules 是提前設置好一個比較花費大量時間運算或經常運算的表達式,其結果保存成一組新的時間序列數據。當需要查詢的時候直接會返回已經計算好的結果,這樣會比直接查詢快,也減輕了PromQl的計算壓力,同時對可視化查詢的時候也很有用,可視化展示每次只需要刷新重復查詢相同的表達式即可。
配置示范如下:

 - expr: node_cpu_seconds_total * on (node) group_left(type) ecms_node_type * on (node) group_left(label_cloud_product) kube_node_labels
   record: ecms_node_cpu_seconds_total
 - expr: avg by (mode,node_name)(irate(ecms_node_cpu_seconds_total{label_cloud_product=""}[5m]) OR irate(ecms_node_cpu_seconds_total{label_cloud_product="enabled",type="Physical"}[5m])) * 100
   record: ecms_node_cpu_utilization

ecms_node_cpu_seconds_total:
expr_rules 為:
node_cpu_seconds_total * on (node) group_left(type) ecms_node_type * on (node) group_left(label_cloud_product) kube_node_labels

將這個expr拆分為三塊:
1.node_cpu_seconds_total
2.on (node) group_left(type) ecms_node_type
3.on (node) group_left(label_cloud_product) kube_node_labels
在node_cpu_seconds_total側包括ecms_node_type的type標簽

其中:on表示指定要參與匹配的標簽,ignoring表示忽視不參與匹配的標簽
表示kube_node_labels,ecms_node_type,node_cpu_seconds_total 這三個metric用僅用node標簽匹配,其他標簽不參與。根據node的匹配度,然后把label_cloud_product和type標簽,添加到node_cpu_seconds_total中。這邊的group_left的有點類似sql中的left join的意思。即node_cpu_seconds_total中如存在node標簽,而在ecms_node_type和kube_node_labels不存在的話,這個sample是要匹配上的,而不是廢棄。

這邊的SQL語法可以學習下 PromQL 語法

ecms_node_cpu_utilization:
這個較為簡單,表示ecms_node_cpu_seconds_total這個metric的標簽為label_cloud_product為空的sample,或者是標簽為label_cloud_product=enable,type="Physical"的sample5分鐘采樣的irate算法,最后按照mode,node_name求平均值

irate算法
irate 適用于變化頻率高的 counter 類型數據,計算范圍向量中時間序列的每秒平均增長率。基于最后兩個數據點。當 counter 出現單調性中斷會自動進行調整,與 rate 不同的是,irate 只會選取時間范圍內最近的兩個點計算,當選定的時間范圍內僅包含兩個數據點時,不考慮外推情況,rate 和 irate 并無明顯區別。

group_left用法
Many-to-one / one-to-many 向量匹配
這種匹配模式下,某一邊會有多個元素跟另一邊的元素匹配。這時就需要使用 group_left 或 group_right 組修飾符來指明哪邊匹配元素較多,左邊多則用 group_left,右邊多則用 group_right。其語法如下:

<vector expr> <bin-op> ignoring(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> ignoring(<label list>) group_right(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_left(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) group_right(<label list>) <vector expr>

參考:
https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/
https://prometheus.io/docs/prometheus/latest/querying/functions/
https://blog.csdn.net/ActionTech/article/details/105786785
https://github.com/chenjiandongx/prometheus101

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容