1. 程式人生 > 實用技巧 >Prometheus監控告警淺析

Prometheus監控告警淺析

此文轉載自:https://my.oschina.net/OutOfMemory/blog/4706596
大咖揭祕Java人都栽在了哪?點選免費領取《大廠面試清單》,攻克面試難關~>>>

前言

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

監控架構

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

整個流程大致分為收集資料,儲存資料,展示監控資料,監控告警;核心元件包括:Exporters,Prometheus Server,AlertManager,PushGateway;

  • 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
資料庫 MySQL Exporter, Redis Exporter, MongoDB Exporter等
硬體 Node Exporter等
訊息佇列 Kafka Exporter, RabbitMQ Exporter等
HTTP服務 Apache Exporter, Nginx Exporter等
儲存 HDFS Exporter等
API服務 Docker Hub Exporter, GitHub Exporter等
其他 JIRA Exporter, Jenkins Exporter, Confluence Exporter等

官方提供的第三方Exporter: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格式.

<metricname>{<labelname>=<labelvalue>, ...}

主要分為三個部分 各個部分需符合相關的正則表示式

  • metric name:指標的名稱,主要反映被監控樣本的含義a-zA-Z_:*_
  • label name: 標籤 反映了當前樣本的特徵維度[a-zA-Z0-9_]*
  • 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

更多: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

更多: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

更多:PromQL

告警

告警的流程大致就是:在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;
更多:alerting

安裝與配置

下面看一個幾個核心元件的安裝包括: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 將會自動配置PrometheusMeterRegistryCollectorRegistry來以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 POSThttp:``//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:用於跟蹤分散式的事件;

更多:Micrometer

總結

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