Prometheus 是一個開源監控系統,它前身是 SoundCloud的告警工具包。從 2012 年開始,許多公司和組織開始使用 Prometheus。該項目的開發人員和用戶社區很是活躍,愈來愈多的開發人員和用戶參與到該項目中。目前它是一個獨立的開源項目,且不依賴於任何公司。爲了強調這點和明確該項目治理結構,Prometheus 在 2016 年繼Kurberntes 以後,加入了 Cloud Native Computing Foundation。node
Prometheus 從根本上存儲的全部數據都是時間序列數據(Time Serie Data,簡稱時序數據)。時序數據是具備時間戳的數據流,該數據流屬於某個度量指標(Metric)和該度量指標下的多個標籤(Label)。除了提供存儲功能,Prometheus 還能夠利用查詢表達式來執行很是靈活和複雜的查詢。linux
每一個時間序列(Time Serie,簡稱時序)由度量指標和一組標籤鍵值對惟一肯定。ios
度量指標名稱描述了被監控系統的某個測量特徵(好比 http_requests_total 表示 http 請求總數)。度量指標名稱由 ASCII 字母、數字、下劃線和冒號組成,須匹配正則表達式 [a-zA-Z_:][a-zA-Z0-9_:]*
。git
標籤開啓了 Prometheus 的多維數據模型。對於同一個度量指標,不一樣標籤值組合會造成特定維度的時序。Prometheus 的查詢語言能夠經過度量指標和標籤對時序數據進行過濾和聚合。改變任何度量指標上的任何標籤值,都會造成新的時序。標籤名稱能夠包含 ASCII 字母、數字和下劃線,須匹配正則表達式 [a-zA-Z_][a-zA-Z0-9_]*
,帶有 _ 下劃線的標籤名稱保留爲內部使用。標籤值能夠包含任意 Unicode 字符,包括中文。github
採樣值(Sample)web
時序數據其實就是一系列採樣值。每一個採樣值包括:正則表達式
註解(Notation)docker
一個註解由一個度量指標和一組標籤鍵值對構成。形式以下:shell
[metric name]{[label name]=[label value], ...}
複製代碼
例如,度量指標爲 api_http_requests_total,標籤爲 method="POST"、handler="/messages" 的註解表示以下:數據庫
api_http_requests_total{method="POST", handler="/messages"}
複製代碼
計數器是一種累計型的度量指標,它是一個只能遞增的數值。計數器主要用於統計相似於服務請求數、任務完成數和錯誤出現次數這樣的數據。
計量器表示一個既能夠增長, 又能夠減小的度量指標值。計量器主要用於測量相似於溫度、內存使用量這樣的瞬時數據。
直方圖(Histogram)
直方圖對觀察結果(一般是請求持續時間或者響應大小這樣的數據)進行採樣,並在可配置的桶中對其進行統計。有如下幾種方式來產生直方圖(假設度量指標爲 ):
<basename>_bucket{le="<upper inclusive bound>"}
<basename>_sum
<basename>_count
,也等同於把全部採樣值放到一個桶裏來計數 <basename>_bucket{le="+Inf"}
彙總(Summary)
相似於直方圖,彙總也對觀察結果進行採樣。除了能夠統計採樣值總和和總數,它還可以按分位數統計。有如下幾種方式來產生彙總(假設度量指標爲 ):
<basename>{quantile="<φ>"}
<basename>_sum
<basename>_count
在 Prometheus 裏,能夠從中抓取採樣值的端點稱爲實例,爲了性能擴展而複製出來的多個這樣的實例造成了一個任務。
例以下面的 api-server 任務有四個相同的實例:
job: api-server
instance 1: 1.2.3.4:5670
instance 2: 1.2.3.4:5671
instance 3: 5.6.7.8:5670
instance 4: 5.6.7.8:5671
複製代碼
Prometheus 抓取完採樣值後,會自動給採樣值添加下面的標籤和值:
另外每次抓取時,Prometheus 還會自動在如下時序裏插入採樣值:
up{job="[job-name]", instance="instance-id"}
:採樣值爲 1 表示實例健康,不然爲不健康scrape_duration_seconds{job="[job-name]", instance="[instance-id]"}
:採樣值爲本次抓取消耗時間scrape_samples_post_metric_relabeling{job="<job-name>", instance="<instance-id>"}
:採樣值爲從新打標籤後的採樣值個數scrape_samples_scraped{job="<job-name>", instance="<instance-id>"}
:採樣值爲本次抓取到的採樣值個數分組將相似性質的警報分類爲單個通知。在許多系統一次性失敗而且數百到數千個警報可能同時發生的較大中斷期間,這尤爲有用。
示例:發生網絡分區時,羣集中正在運行數十或數百個服務實例。一半的服務實例沒法再訪問數據庫。Prometheus中的警報規則配置爲在每一個服務實例沒法與數據庫通訊時發送警報。結果,數百個警報被髮送到Alertmanager。
做爲用戶,人們只想得到單個頁面,同時仍可以確切地看到哪些服務實例受到影響。所以,能夠將Alertmanager配置爲按羣集和alertname對警報進行分組,以便發送單個緊湊通知。
經過配置文件中的路由樹配置警報的分組,分組通知的定時以及這些通知的接收器。
若是某些其餘警報已經觸發,則抑制是抑制某些警報的通知的概念。示例:正在觸發警報,通知沒法訪問整個集羣。Alertmanager能夠配置爲在該特定警報觸發時將與該集羣有關的全部其餘警報靜音。這能夠防止數百或數千個與實際問題無關的觸發警報的通知。經過Alertmanager的配置文件配置禁止。
沉默是在給定時間內簡單地靜音警報的簡單方法。基於匹配器配置靜默,就像路由樹同樣。檢查傳入警報它們是否匹配活動靜默的全部相等或正則表達式匹配器。若是他們這樣作,則不會發送該警報的通知。在Alertmanager的Web界面中配置了靜音。
Alertmanager對其客戶的行爲有特殊要求。這些僅適用於不使用Prometheus發送警報的高級用例。
Alertmanager支持配置以建立用於高可用性的集羣。這可使用--cluster- *標誌進行配置。重要的是不要在Prometheus和它的Alertmanagers之間加載平衡流量,而是將Prometheus指向全部Alertmanagers的列表。
cd /opt && wget https://github.com/prometheus/prometheus/releases/download/v2.12.0/prometheus-2.12.0.linux-amd64.tar.gz
tar -zxf prometheus-2.12.0.linux-amd64.tar.gz
mv prometheus-2.12.0.linux-amd64 prometheus
chown root.root prometheus -R
# 配置爲服務
cat >/usr/lib/systemd/system/prometheus.service <<EOF
[Unit]
Description=Prometheus
Documentation=https://prometheus.io/
After=network.target
[Service]
Type=simple
ExecStart=/opt/prometheus/prometheus --config.file=/opt/prometheus/prometheus.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 設置服務開機自啓動
systemctl enable prometheus
systemctl start prometheus
# 直接啓動
nohup ./prometheus --config.file=prometheus.yml 2>&1 1>prometheus.log &
# 查看服務
[root@VM_0_13_centos pushgateway]# netstat -lntup |grep prometheus
tcp6 0 0 :::9090 :::* LISTEN 16655/prometheus
複製代碼
$ go get github.com/prometheus/prometheus/cmd/...
$ prometheus --config.file=your_config.yml
# 或者make build
$ mkdir -p $GOPATH/src/github.com/prometheus
$ cd $GOPATH/src/github.com/prometheus
$ git clone https://github.com/prometheus/prometheus.git
$ cd prometheus
$ make build
$ ./prometheus --config.file=your_config.yml
複製代碼
docker run --name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus
複製代碼
cd /opt && wget -c https://github.com/prometheus/alertmanager/releases/download/v0.18.0/alertmanager-0.18.0.linux-amd64.tar.gz
tar zxf alertmanager-0.18.0.linux-amd64.tar.gz
mv alertmanager-0.18.0.linux-amd64 alertmanager
chown root.root alertmanager -R
# 配置服務
cat >/usr/lib/systemd/system/alertmanager.service <<EOF
[Unit]
Description=Alertmanager
Documentation=https://prometheus.io/
After=network.target
[Service]
Type=simple
ExecStart=/opt/alertmanager/alertmanager --config.file=/opt/alertmanager/alertmanager.yml
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 設置服務開機自啓動
systemctl enable alertmanager
systemctl start alertmanager
# 直接啓動
nohup ./alertmanager --config.file=alertmanager.yml 2>&1 1>alertmanager.log &
# 查看服務
[root@VM_0_13_centos pushgateway]# netstat -lntup |grep alertmanager
tcp6 0 0 :::9094 :::* LISTEN 17237/alertmanager
tcp6 0 0 :::9093 :::* LISTEN 17237/alertmanager
udp6 0 0 :::9094 :::* 17237/alertmanager
複製代碼
$ GO15VENDOREXPERIMENT=1 go get github.com/prometheus/alertmanager/cmd/...
# cd $GOPATH/src/github.com/prometheus/alertmanager
$ alertmanager --config.file=<your_file>
# 手動源碼構建
$ mkdir -p $GOPATH/src/github.com/prometheus
$ cd $GOPATH/src/github.com/prometheus
$ git clone https://github.com/prometheus/alertmanager.git
$ cd alertmanager
$ make build
$ ./alertmanager --config.file=<your_file>
# amtool構建
$ make build BINARIES=amtool
複製代碼
docker pull quay.io/prometheus/alertmanager
複製代碼
利用node_export來監控主機,官方也提供了不少其餘的export能夠用來直接使用
cd /opt && wget -c https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz
tar zxf node_exporter-0.18.1.linux-amd64.tar.gz
mv node_exporter-0.18.1.linux-amd64 node_exporter
chown root.root node_exporter -R
# 配置服務
cat >/usr/lib/systemd/system/node_exporter.service <<EOF
[Unit]
Description=node_exporter
Documentation=https://prometheus.io/
After=network.target
[Service]
Type=simple
ExecStart=/opt/node_exporter/node_exporter
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 設置服務開機自啓動
systemctl enable node_exporter
systemctl start node_exporter
# 直接啓動
nohup ./node_exporter --config.file=node_exporter.yml 2>&1 1>node_exporter.log &
# 查看服務
[root@VM_0_13_centos pushgateway]# netstat -lntup |grep node_export
tcp6 0 0 :::9100 :::* LISTEN 4551/node_exporter
複製代碼
cd /opt && wget -c https://github.com/prometheus/pushgateway/releases/download/v0.9.1/pushgateway-0.9.1.linux-amd64.tar.gz
tar zxf pushgateway-0.9.1.linux-amd64.tar.gz
mv pushgateway-0.9.1.linux-amd64 pushgateway
chown root.root pushgateway -R
# 配置服務
cat >/usr/lib/systemd/system/pushgateway.service <<EOF
[Unit]
Description=pushgateway
Documentation=https://prometheus.io/
After=network.target
[Service]
Type=simple
ExecStart=/opt/pushgateway/pushgateway
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 設置服務開機自啓動
systemctl enable pushgateway
systemctl start pushgateway
# 直接啓動
nohup ./pushgateway --config.file=node_exporter.yml 2>&1 1>node_exporter.log &
# 查看服務
[root@VM_0_13_centos pushgateway]# netstat -lntup |grep push
tcp6 0 0 :::9091 :::* LISTEN 5982/pushgateway
複製代碼
echo "some_metric 3.14" | curl --data-binary @- http://localhost:9091/metrics/job/some_job
複製代碼
cat <<EOF | curl --data-binary @- http://localhost:9091/metrics/job/some_job/instance/some_instance
# TYPE some_metric counter
some_metric{label="val1"} 42
# TYPE another_metric gauge
# HELP another_metric Just an example.
another_metric 2398.283
EOF
複製代碼
wget https://dl.grafana.com/oss/release/grafana-6.3.3-1.x86_64.rpm
sudo yum localinstall grafana-6.3.3-1.x86_64.rpm -y
systemctl enable grafana-server.service
systemctl start grafana-server.service
# web頁面3000 登陸信息:admin/admin
# 安裝插件
grafana-cli plugins install grafana-piechart-panel
systemctl restart grafana-server
複製代碼
添加prometheus,填寫prometheus的管理地址
經過https://grafana.com/grafana/dashboards中獲取
# 修改/etc/grafana/grafana.ini
[smtp]
enabled = true
host = smtp.163.com:465
user = 18329903316
# If the password contains # or ; you have to wrap it with trippel quotes. Ex """#password;"""
password = xxxxxxxxxxxx
;cert_file =
;key_file =
;skip_verify = false
from_address = 18329903316@163.com
;from_name = Grafana
;ehlo_identity = dashboard.example.com
複製代碼
⚠️:Template variables are not supported in alert queries,在查詢中不能使用模版語法,否則沒法建立告警
告警測試
查看告警歷史
告警觸發
PromQL(Prometheus Query Language)是 Prometheus 本身開發的表達式語言,語言表現力很豐富,內置函數也不少。使用它能夠對時序數據進行篩選和聚合。
PromQL 表達式計算出來的值有如下幾種類型:
瞬時向量選擇器
瞬時向量選擇器用來選擇一組時序在某個採樣點的採樣值。
最簡單的狀況就是指定一個度量指標,選擇出全部屬於該度量指標的時序的當前採樣值。好比下面的表達式:
http_requests_total
複製代碼
能夠經過在後面添加用大括號包圍起來的一組標籤鍵值對來對時序進行過濾。好比下面的表達式篩選出了 job 爲 prometheus,而且 group 爲 canary 的時序:
http_requests_total{job="prometheus", group="canary"}
複製代碼
匹配標籤值時能夠是等於,也可使用正則表達式。總共有下面幾種匹配操做符:
下面的表達式篩選出了 environment 爲 staging 或 testing 或 development,而且 method 不是 GET 的時序:
http_requests_total{environment=~"staging|testing|development",method!="GET"}
複製代碼
度量指標名可使用內部標籤 __name__
來匹配,表達式 http_requests_total
也能夠寫成 {__name__="http_requests_total"}
。表達式 {__name__=~"job:.*"}
匹配全部度量指標名稱以 job:
打頭的時序。
區間向量選擇器
區間向量選擇器相似於瞬時向量選擇器,不一樣的是它選擇的是過去一段時間的採樣值。能夠經過在瞬時向量選擇器後面添加包含在 []
裏的時長來獲得區間向量選擇器。好比下面的表達式選出了全部度量指標爲 http_requests_total 且 job 爲 prometheus 的時序在過去 5 分鐘的採樣值。
http_requests_total{job="prometheus"}[5m]
複製代碼
時長的單位能夠是下面幾種之一:
偏移修飾器
前面介紹的選擇器默認都是以當前時間爲基準時間,偏移修飾器用來調整基準時間,使其往前偏移一段時間。偏移修飾器緊跟在選擇器後面,使用 offset
來指定要偏移的量。好比下面的表達式選擇度量名稱爲 http_requests_total 的全部時序在 5 分鐘前的採樣值。
http_requests_total offset 5m
複製代碼
下面的表達式選擇 http_requests_total 度量指標在 1 周前的這個時間點過去 5 分鐘的採樣值。
http_requests_total[5m] offset 1w
複製代碼
PromQL 的二元操做符支持基本的邏輯和算術運算,包含算術類、比較類和邏輯類三大類。
算術類二元操做符
算術類二元操做符有如下幾種:
算術類二元操做符能夠使用在標量與標量、向量與標量,以及向量與向量之間
二元操做符上下文裏的向量特指瞬時向量,不包括區間向量。
比較類二元操做符
比較類二元操做符有如下幾種:
比較類二元操做符一樣能夠使用在標量與標量、向量與標量,以及向量與向量之間。默認執行的是過濾,也就是保留值。能夠經過在運算符後面跟 bool
修飾符來使得返回值 0 和 1,而不是過濾。
邏輯類二元操做符
邏輯操做符僅用於向量與向量之間。
具體運算規則以下:
vector1 and vector2
的結果由在 vector2 裏有匹配(標籤鍵值對組合相同)元素的 vector1 裏的元素組成。vector1 or vector2
的結果由全部 vector1 裏的元素加上在 vector1 裏沒有匹配(標籤鍵值對組合相同)元素的 vector2 裏的元素組成。vector1 unless vector2
的結果由在 vector2 裏沒有匹配(標籤鍵值對組合相同)元素的 vector1 裏的元素組成。二元操做符優先級
PromQL 的各種二元操做符運算優先級以下:
前面算術類和比較類操做符都須要在向量之間進行匹配。共有兩種匹配類型,one-to-one
和 many-to-one
/ one-to-many
。
One-to-one 向量匹配
相同則爲匹配,而且只會有一個匹配元素。可使用 ignoring
關鍵詞來忽略不參與匹配的標籤,或者使用 on
關鍵詞來指定要參與匹配的標籤。語法以下:
<vector expr> <bin-op> ignoring(<label list>) <vector expr>
<vector expr> <bin-op> on(<label list>) <vector expr>
複製代碼
好比對於下面的輸入:
method_code:http_errors:rate5m{method="get", code="500"} 24
method_code:http_errors:rate5m{method="get", code="404"} 30
method_code:http_errors:rate5m{method="put", code="501"} 3
method_code:http_errors:rate5m{method="post", code="500"} 6
method_code:http_errors:rate5m{method="post", code="404"} 21
method:http_requests:rate5m{method="get"} 600
method:http_requests:rate5m{method="del"} 34
method:http_requests:rate5m{method="post"} 120
複製代碼
執行下面的查詢:
method_code:http_errors:rate5m{code="500"} / ignoring(code) method:http_requests:rate5m
複製代碼
獲得的結果爲:
{method="get"} 0.04 // 24 / 600
{method="post"} 0.05 // 6 / 120
複製代碼
也就是每一種 method 裏 code 爲 500 的請求數佔總數的百分比。因爲 method 爲 put 和 del 的沒有匹配元素因此沒有出如今結果裏。
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>
複製代碼
組修飾符只適用於算術類和比較類操做符。
對於前面的輸入,執行下面的查詢:
method_code:http_errors:rate5m / ignoring(code) group_left method:http_requests:rate5m
複製代碼
將獲得下面的結果:
{method="get", code="500"} 0.04 // 24 / 600
{method="get", code="404"} 0.05 // 30 / 600
{method="post", code="500"} 0.05 // 6 / 120
{method="post", code="404"} 0.175 // 21 / 120
複製代碼
也就是每種 method 的每種 code 錯誤次數佔每種 method 請求數的比例。這裏匹配的時候 ignoring 了 code,才使得兩邊能夠造成 Many-to-one 形式的匹配。因爲左邊多,因此須要使用 group_left 來指明。
Many-to-one / one-to-many 過於高級和複雜,要儘可能避免使用。不少時候經過 ignoring 就能夠解決問題。
PromQL 的聚合操做符用來將向量裏的元素聚合得更少。總共有下面這些聚合操做符:
聚合操做符語法以下:
<aggr-op>([parameter,] <vector expression>) [without|by (<label list>)]
複製代碼
其中 without
用來指定不須要保留的標籤(也就是這些標籤的多個值會被聚合),而 by
正好相反,用來指定須要保留的標籤(也就是按這些標籤來聚合)。
下面來看幾個示例:
sum(http_requests_total) without (instance)
複製代碼
http_requests_total 度量指標帶有 application、instance 和 group 三個標籤。上面的表達式會獲得每一個 application 的每一個 group 在全部 instance 上的請求總數。效果等同於下面的表達式:
sum(http_requests_total) by (application, group)
複製代碼
下面的表達式能夠獲得全部 application 的全部 group 的全部 instance 的請求總數。
sum(http_requests_total)
複製代碼
Prometheus 內置了一些函數來輔助計算,下面介紹一些典型的,完整的列表請參考 官方文檔。
將報警集成到睿象雲
# 編輯prometheus.yml
alerting:
alertmanagers:
- static_configs:
- targets:
- 'localhost:9093'
rule_files:
- "onealter.yml"
複製代碼
# 編寫onealter.yml
groups:
- name: test-rule
rules:
- alert: 節點內存使用量
expr: (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes+node_memory_Buffers_bytes+node_memory_Cached_bytes )) / node_memory_MemTotal_bytes * 100 > 40
for: 1m
labels:
user: prometheus
annotations:
summary: "{{$labels.instance}}:內存超過40%"
description: "{{$labels.instance}}:內存超過40%"
複製代碼
# 編輯
global:
resolve_timeout: 5m
route:
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receiver: 'team-X-pager'
receivers:
- name: 'team-X-pager'
webhook_configs:
- url: 'http://api.aiops.com/alert/api/event/prometheus/f307ded7-9a96-4e34-101d-dfc421a8743a'
send_resolved: true
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'dev', 'instance']
複製代碼