淺析開源監控告警系統 Prometheus
前言
最近有個新項目需要搞一套完整的監控告警系統,我們使用了開源監控告警系統 Prometheus;其功能強大,可以很方便對其進行擴展,並且可以安裝和使用簡單;本文首先介紹 Prometheus 的整個監控流程;然後介紹如何收集監控數據,如何展示監控數據,如何觸發告警;最後展示一個業務系統監控的 demo。
監控架構
Prometheus 的整個架構流程可以參考如下圖片:
-
Exporters:監控數據採集器,將數據通過 Http 的方式暴露給 Prometheus Server;
-
Prometheus Server:負責對監控數據的獲取,存儲以及查詢;獲取的監控數據需要是指定的 Metrics 格式,這樣才能處理監控數據;對於查詢 Prometheus 提供了 PromQL 方便對數據進行查詢彙總,當然 Prometheus 本身也提供了 Web UI;
-
AlertManager:Prometheus 支持通過 PromQL 來創建告警規則,如果滿足規則則創建一條告警,後續的告警流程就交給 AlertManager,其提供了多種告警方式包括 email,webhook 等方式;
-
PushGateway:正常情況下 Prometheus Server 能夠直接與 Exporter 進行通信,然後 pull 數據;當網絡需求無法滿足時就可以使用 PushGateway 作爲中轉站了;
收集數據
Exporter 的主要功能就是收集數據,然後將數據通過 http 的方式暴露給 Prometheus,然後 Prometheus 通過定期拉取的方式來獲取監控數據;
數據的來源多種多樣包括:系統級監控數據比如節點的 cpu,io 等,中間件比如 mysql,mq 等,進程級監控比如 jvm 等,業務監控數據等;除了監控的業務數據每個系統可能不一樣,除此之外其他的監控數據其實每個系統都是大同小異的;所以在 Exporter 的來源分成了兩類:社區提供的,用戶自定義的;
Exporter 來源
- 社區提供
- 用戶自定義
除了以上提供的第三方 Exporter,用戶也可以自定義 Exporter,當然需要基於 Prometheus 提供的 Client Library 創建自己的 Exporter 程序,提供了對多種語言的支持包括:Go、Java/Scala、Python、Ruby 等;
Exporter 運行方式
從 Exporter 的運行方式上來講,又可以分爲:獨立運行和集成到應用中;
- 獨立運行
像 mysql,redis,mq 這些中間件本身時不支持 Prometheus,這時候就可以提供一個獨立的 Exporter,通過中間件對外提供的監控數據 API,來獲取監控數據,然後轉換成 Prometheus 可以識別的數據格式;
- 集成到應用中
一些需要自定義監控指標的系統,可以通過 Prometheus 提供的 Client Library 將監控數據在系統內部提供給 Prometheus;
數據格式
Prometheus 通過輪詢的方式從 Exporter 獲取監控數據,當然數據需要遵循一定的格式,不然 Prometheus 也是無法識別的,這個格式就是 Metrics 格式.
<metric name>{<label name>=<label value>, ...}
主要分爲三個部分 各個部分需符合相關的正則表達式
可以看一個 JVM 的監控數據:
# HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management
# TYPE jvm_memory_max_bytes gauge
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Metaspace",} -1.0
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Eden Space",} 1.033895936E9
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Code Cache",} 2.5165824E8
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Compressed Class Space",} 1.073741824E9
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Survivor Space",} 2621440.0
jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Old Gen",} 2.09190912E9
更多:https://prometheus.io/docs/concepts/data_model/
數據類型
Prometheus 定義了 4 種不同的指標類型 (metric type):Counter(計數器)、Gauge(儀表盤)、Histogram(直方圖)、Summary(摘要)
- Counter
只增不減的計數器,比如可以在應用程序中記錄某些事件發生的次數;常見的監控指標,如 http_requests_total;
# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the young generation memory pool after one GC to before the next
# TYPE jvm_gc_memory_allocated_bytes_total counter
jvm_gc_memory_allocated_bytes_total{application="springboot-actuator-prometheus-test",} 6.3123664E9
- Gauge
側重於反應系統的當前狀態,可增可減;常見指標如:node_memory_MemFree(主機當前空閒的內容大小)、node_memory_MemAvailable(可用內存大小);
# HELP jvm_threads_live_threads The current number of live threads including both daemon and non-daemon threads
# TYPE jvm_threads_live_threads gauge
jvm_threads_live_threads{application="springboot-actuator-prometheus-test",} 20.0
- Histogram 和 Summary
主用用於統計和分析樣本的分佈情況
# HELP jvm_gc_pause_seconds Time spent in GC pause
# TYPE jvm_gc_pause_seconds summary
jvm_gc_pause_seconds_count{action="end of minor GC",application="springboot-actuator-prometheus-test",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of minor GC",application="springboot-actuator-prometheus-test",cause="Metadata GC Threshold",} 0.008
jvm_gc_pause_seconds_count{action="end of minor GC",application="springboot-actuator-prometheus-test",cause="Allocation Failure",} 38.0
jvm_gc_pause_seconds_sum{action="end of minor GC",application="springboot-actuator-prometheus-test",cause="Allocation Failure",} 0.134
jvm_gc_pause_seconds_count{action="end of major GC",application="springboot-actuator-prometheus-test",cause="Metadata GC Threshold",} 1.0
jvm_gc_pause_seconds_sum{action="end of major GC",application="springboot-actuator-prometheus-test",cause="Metadata GC Threshold",} 0.073
更多:https://prometheus.io/docs/concepts/metric_types/
展示數據
Prometheus 可以通過內置的 Prometheus UI 以及 Grafana 來展示數據,Prometheus UI 是 Prometheus 自帶的 Web UI,可以方便的用來執行測試 PromQL;
Grafana 是一款採用 go 語言編寫的開源應用,允許您從 Elasticsearch,Prometheus,Graphite,InfluxDB 等各種數據源中獲取數據,並通過精美的圖形將其可視化;
- Prometheus UI
主界面大致如下:
所有註冊的 Exporter 都可以在 UI 查看,告警也可以在 Alerts 界面查看,同時也可以執行 PromQL 來查詢監控數據,進行展示;
- Grafana
在 Grafana 中每個監控查詢都可以做成一個面板,面板可以有多種展示方式,比如:
PromQL 簡介
PromQL 是 Prometheus 內置的數據查詢語言,可以類比成 SQL;提供了豐富的查詢,邏輯運算,聚合函數等等;
- 操作符
操作符包括:數學運算符,邏輯運算符,布爾運算符等等;比如:
rabbitmq_queue_messages>0
- 聚合函數
提供了大量的內置函數,比如: sum
(求和), min
(最小值),max
(最大值),avg
(平均值) 等等;
sum(rabbitmq_queue_messages)>0
更多:https://prometheus.io/docs/prometheus/latest/querying/basics/
告警
告警的流程大致就是:在 prometheus 中通過 PromQL 配置告警規則,如果規則成立,則發送一條消息給接收者,這裏的接收者其實就是 AlertManager,AlertManager 可以配置多種告警方法如 email,webhook 等;
自定義告警規則
Prometheus 中的告警規則允許你基於 PromQL 表達式定義告警觸發條件,Prometheus 後端對這些觸發規則進行週期性計算,當滿足觸發條件後則會觸發告警通知;
比如如下告警規則:
- name: queue-messages-warning
rules:
- alert: queue-messages-warning
expr: sum(rabbitmq_queue_messages{job='rabbit-state-metrics'}) > 500
labels:
team: webhook-warning
annotations:
summary: High queue-messages usage detected
threshold: 500
current: '{{ $value }}'
-
alert:告警規則的名稱;
-
expr:基於 PromQL 表達式告警觸發條件;
-
labels:自定義標籤,通過其關聯到具體 Alertmanager 上;
-
annotations:用於指定一組附加信息,比如用於描述告警詳細信息的文字等;
AlertManager
AlertManager 是一個告警管理器,它提供了 豐富的告警方式包括:電子郵件,pagerduty,OpsGenie, webhook 等;在如上的告警規則表達式成功之後,可以將告警發送給 AlertManager,由 AlertManager 來講告警以更加豐富的方式告訴給開發人員;
global:
resolve_timeout: 5m
route:
receiver: webhook
group_wait: 30s
group_interval: 1m
repeat_interval: 5m
group_by:
- alertname
routes:
- receiver: webhook
group_wait: 10s
match:
team: webhook-warning
receivers:
- name: webhook
webhook_configs:
- url: 'http://ip:port/api/v1/monitor/alert-receiver'
send_resolved: true
以上即是在 AlertManager 中配置的路由和接收者 webhook;
更多:https://prometheus.io/docs/alerting/latest/overview/
安裝與配置
下面看一個幾個核心組件的安裝包括:Prometheus,AlertManager,Exporter,Grafana;所有組件的安裝都是基於 k8s 平臺;
Prometheus 和 AlertManager
如下 yml 文件分別安裝了 Prometheus 和 AlertManager,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: '18'
generation: 18
labels:
app: prometheus
name: prometheus
namespace: monitoring
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: prometheus
template:
metadata:
labels:
app: prometheus
spec:
containers:
- image: 'prom/prometheus:latest'
imagePullPolicy: Always
name: prometheus-0
ports:
- containerPort: 9090
name: p-port
protocol: TCP
resources:
requests:
cpu: 250m
memory: 512Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/prometheus
name: config-volume
- image: 'prom/alertmanager:latest'
imagePullPolicy: Always
name: prometheus-1
ports:
- containerPort: 9093
name: a-port
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/alertmanager
name: alertcfg
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: data
persistentVolumeClaim:
claimName: monitoring-nfs-pvc
- configMap:
defaultMode: 420
name: prometheus-config
name: config-volume
- configMap:
defaultMode: 420
name: alert-config
name: alertcfg
其中指定了兩個鏡像分別是 prom/prometheus:latest 和 prom/alertmanager:latest,以及指定對外的端口;因爲啓動兩個容器需要用到配置文件 prometheus.yml 和 alertmanager.yml,通過在 volumes 中配置了 prometheus-config 和 alert-config 兩個配置字典:
prometheus.yml 配置如下:
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- 'rabbitmq_warn.yml'
alerting:
alertmanagers:
- static_configs:
- targets: ['127.0.0.1:9093']
scrape_configs:
- job_name: 'rabbit-state-metrics'
static_configs:
- targets: ['ip:port']
其中配置了 alertmanager,以及規則文件 rabbitmq_warn.yml,還有配置了需要收集監控信息的 exporter,也就是這邊的 job_name,可以配置多個;
- 查看 Exporter
啓動 prometheus 之後可以在 prometheus web ui 中查看相關 exporter 以及告警規則:
可以在 status/targets 目錄下查看到當前的所有 exporter,如果狀態都爲 up 表示,表示 prometheus 已經可以接受監控數據了,比如我這裏配置的接收 rabbitmq 相關監控數據;
- 查看 Alerts
配置的相關告警也可以在 prometheus web ui 中查看:
如果告警規則成立會顯示紅色,當然同時也會發送消息給 alertmanager;
Grafana
grafana 安裝 yml 文件如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: '1'
generation: 1
labels:
app: grafana
name: grafana
namespace: monitoring
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: grafana
template:
metadata:
labels:
app: grafana
spec:
containers:
- image: grafana/grafana
imagePullPolicy: Always
name: grafana
ports:
- containerPort: 3000
protocol: TCP
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
安裝完之後,就可以使用 grafana 了,Grafana 需要能獲取到 prometheus 的數據,所以需要配置數據源 data sources:
這時候就可以在裏面創建監控看板了,並且在裏面可以直接使用 PromQL:
Exporter
大部分我們使用的中間件都是通過獨立模式部署的,比如我這裏使用的 rabbitmq:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: '3'
labels:
k8s-app: rabbitmq-exporter
name: rabbitmq-exporter
namespace: monitoring
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 2
selector:
matchLabels:
k8s-app: rabbitmq-exporter
template:
metadata:
labels:
k8s-app: rabbitmq-exporter
spec:
containers:
- env:
- name: PUBLISH_PORT
value: '9098'
- name: RABBIT_CAPABILITIES
value: 'bert,no_sort'
- name: RABBIT_USER
value: xxxx
- name: RABBIT_PASSWORD
value: xxxx
- name: RABBIT_URL
value: 'http://ip:15672'
image: kbudde/rabbitmq-exporter
imagePullPolicy: IfNotPresent
name: rabbitmq-exporter
ports:
- containerPort: 9098
protocol: TCP
這裏啓動了一個 rabbitmq-exporter 服務,端口爲 9098,並且監聽 RabbitMQ 的 15672 接口,獲取其中的指標數據,轉換成 prometheus 可以識別的 metrics;如果需要對業務進行監控,這時候就需要自定義監控了。
MicroMeter
SpringBoot 本身提供了健康檢查,度量,指標收集和監控,怎麼把這些數據暴露給 Prometheus,這就要用到 Micrometer ,Micrometer 爲 Java 平臺上的性能數據收集提供了一個通用的 API,應用程序只需要使用 Micrometer 的通用 API 來收集性能指標即可。Micrometer 會負責完成與不同監控系統的適配工作。
添加依賴
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
添加上述依賴項之後,Spring Boot 將會自動配置 PrometheusMeterRegistry
和 CollectorRegistry
來以 Prometheus 可以抓取的格式收集和導出指標數據;
所有的相關數據,都會在 Actuator 的 /prometheus
端點暴露出來。Prometheus 可以抓取該端點以定期獲取度量標準數據。
prometheus 端點
啓動 SpringBoot 服務,可以直接訪問 http://ip:8080/actuator/prometheus 地址,可以看到 SpringBoot 已經提供了一些應用公共的監控數據比如 jvm:
# HELP tomcat_sessions_created_sessions_total
# TYPE tomcat_sessions_created_sessions_total counter
tomcat_sessions_created_sessions_total{application="springboot-actuator-prometheus-test",} 1782.0
# HELP tomcat_sessions_active_current_sessions
# TYPE tomcat_sessions_active_current_sessions gauge
tomcat_sessions_active_current_sessions{application="springboot-actuator-prometheus-test",} 365.0
# HELP jvm_threads_daemon_threads The current number of live daemon threads
# TYPE jvm_threads_daemon_threads gauge
jvm_threads_daemon_threads{application="springboot-actuator-prometheus-test",} 16.0
# HELP process_cpu_usage The "recent cpu usage" for the Java Virtual Machine process
# TYPE process_cpu_usage gauge
process_cpu_usage{application="springboot-actuator-prometheus-test",} 0.0102880658436214
# HELP jvm_gc_memory_allocated_bytes_total Incremented for an increase in the size of the young generation memory pool after one GC to before the next
# TYPE jvm_gc_memory_allocated_bytes_total counter
jvm_gc_memory_allocated_bytes_total{application="springboot-actuator-prometheus-test",} 9.13812704E8
# HELP jvm_buffer_count_buffers An estimate of the number of buffers in the pool
# TYPE jvm_buffer_count_buffers gauge
jvm_buffer_count_buffers{application="springboot-actuator-prometheus-test",id="mapped",} 0.0
jvm_buffer_count_buffers{application="springboot-actuator-prometheus-test",id="direct",} 10.0
...
prometheus 配置 target
在 prometheus.yml 中做如下配置:
- job_name: 'springboot-actuator-prometheus-test'
metrics_path: '/actuator/prometheus'
scrape_interval: 5s
basic_auth:
username: 'actuator'
password: 'actuator'
static_configs:
- targets: ['ip:8080']
添加完之後可以重新加載配置:
curl -X POST http:``//ip:9090/-/reload
再次查看 prometheus 的 target:
Grafana
可以增加一個 JVM 的看板,如下所示:
業務埋點
Micrometer 提供一系列原生的 Meter,包括 Timer , Counter , Gauge , DistributionSummary , LongTaskTimer 等。不同的 meter 類型導致有不同的時間序列指標值。例如,單個指標值用 Gauge 表示,計時事件的次數和總時間用 Timer 表示;
-
Counter:允許以固定的數值遞增,該數值必須爲正數;
-
Gauge:獲取當前值的句柄。典型的例子是,獲取集合、map、或運行中的線程數等;
-
Timer:Timer 用於測量短時間延遲和此類事件的頻率。所有 Timer 實現至少將總時間和事件次數報告爲單獨的時間序列;
-
LongTaskTimer:長任務計時器用於跟蹤所有正在運行的長時間運行任務的總持續時間和此類任務的數量;
-
DistributionSummary:用於跟蹤分佈式的事件;
更多:https://micrometer.io/docs/concepts
總結
本文介紹了 prometheus 做監控服務的整個流程,從原理到實例,可以作爲一個入門教程,但是 prometheus 強大之處在於它提供的 PromQL,這個可以根據需求自己去學習;還有就是 Micrometer 埋點接口其實對 prometheus api(simpleclient) 的包裝,方便開發者去使用,可以根據需求去學習即可。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/HcIojxZ4voHCRUQYmwBkRw