淺析開源監控告警系統 Prometheus

前言

最近有個新項目需要搞一套完整的監控告警系統,我們使用了開源監控告警系統 Prometheus;其功能強大,可以很方便對其進行擴展,並且可以安裝和使用簡單;本文首先介紹 Prometheus 的整個監控流程;然後介紹如何收集監控數據,如何展示監控數據,如何觸發告警;最後展示一個業務系統監控的 demo。

監控架構

Prometheus 的整個架構流程可以參考如下圖片:

收集數據

Exporter 的主要功能就是收集數據,然後將數據通過 http 的方式暴露給 Prometheus,然後 Prometheus 通過定期拉取的方式來獲取監控數據;
數據的來源多種多樣包括:系統級監控數據比如節點的 cpu,io 等,中間件比如 mysql,mq 等,進程級監控比如 jvm 等,業務監控數據等;除了監控的業務數據每個系統可能不一樣,除此之外其他的監控數據其實每個系統都是大同小異的;所以在 Exporter 的來源分成了兩類:社區提供的,用戶自定義的;

Exporter 來源

cj6gqv G 官方提供的第三方 Exporter:https://prometheus.io/docs/instrumenting/exporters/

除了以上提供的第三方 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(摘要)

只增不減的計數器,比如可以在應用程序中記錄某些事件發生的次數;常見的監控指標,如 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

側重於反應系統的當前狀態,可增可減;常見指標如: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

主用用於統計和分析樣本的分佈情況

# 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 等各種數據源中獲取數據,並通過精美的圖形將其可視化;

主界面大致如下:

所有註冊的 Exporter 都可以在 UI 查看,告警也可以在 Alerts 界面查看,同時也可以執行 PromQL 來查詢監控數據,進行展示;

在 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 }}'

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,可以配置多個;

啓動 prometheus 之後可以在 prometheus web ui 中查看相關 exporter 以及告警規則:

可以在 status/targets 目錄下查看到當前的所有 exporter,如果狀態都爲 up 表示,表示 prometheus 已經可以接受監控數據了,比如我這裏配置的接收 rabbitmq 相關監控數據;

配置的相關告警也可以在 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 表示;

更多:https://micrometer.io/docs/concepts

總結

本文介紹了 prometheus 做監控服務的整個流程,從原理到實例,可以作爲一個入門教程,但是 prometheus 強大之處在於它提供的 PromQL,這個可以根據需求自己去學習;還有就是 Micrometer 埋點接口其實對 prometheus api(simpleclient) 的包裝,方便開發者去使用,可以根據需求去學習即可。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/HcIojxZ4voHCRUQYmwBkRw