Prometheus監控告警淺析

前言

最近有個新項目需要搞一套完整的監控告警系統,我們使用了開源監控告警系統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 格式.

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

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

  • 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 將會自動配置 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:用於跟蹤分佈式的事件;

更多:Micrometer

總結

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章