1

APM

APM ( Application Performance Management ) 是应用性能管理的缩写,代表了服务的行为、可靠性、性能等的监控和管理。当应用发生故障,利用 APM 设施可以迅速检测并定位到产生故障的原因。

如今的后端服务大都是分布式、微服务化的,做好 APM 尤为重要。APM 包括许多方面工作,包括链路追踪(Tracing)日志(Logging)指标(Metrics)监控与报警 等,对应的开源基础设施也有很多,如 Jaeger/Zipkin (链路跟踪)、ELK (日志)、Prometheus/Zabbix/InfluxDB (指标监控系统)、Grafana (监控展示前端) 等。

今天来说说什么是指标监控,以及总结一下最近学习 Prometheus 的心得,梳理一下知识网络。

Metrics 指标和 Prometheus

我们通常在应用程序中产生日志,日志往往代表的是一个应用或请求生命周期中的一个事件,它是离散的数据。而指标往往代表着应用程序中可量化可聚合分析的数据,例如服务接收的请求量,请求量是一个不断增加的数据,我们可以根据它和时间的对应关系,计算出请求的增长率;再比如,服务的请求延迟,我们可以收集所有的延迟时长,统计出不同的分位数,以衡量服务的整体延迟表现;再比如消息队列系统的任务堆积情况、服务的内存占用、主机的 CPU 占用率等,这些是一个个上下浮动的数值,可以反应一些实时状况,并且通过历史时间的数据,反应过去一段时间的数据波动情况,以预测未来变化。

通过 Prometheus 我们就可以进行这些指标数据的统计、收集、查询/聚合分析、可视化展示、非正常指标的报警等工作。可以把 Prometheus 理解为一个指标收集器与时序数据库 (TSDB) 的集合。

Prometheus 架构

image.png

Prometheus 采用 PULL 的模式定期从应用程序中拉取指标数据。应用程序目标地址可以以静态配置的方式提供,也可以配置服务注册中心,动态的方式获取目标地址,见 文档

组件

  • Exporter 采集指标数据,为 Prometheus server 提供采集接口。Exporter 可以集成在业务代码中,也可以是一个单独的进程服务,来采集其他的服务指标。
  • Pushgateway 是一个中间服务,短生命周期的 job 上传指标到 Pushgateway,server 从 Pushgateway 采集指标。
  • TSDB 是 Prometheus server 内置的时序数据库,用来存储采集的指标数据,并且内置了一套用以查询数据的语法 PromQL。
  • Alertmanager 是独立于 Prometheus server 的一个服务,用来处理报警。Prometheus server 只负责评估报警规则是否被触发,后续的报警通知等工作交由 Alertmanager 处理。

部署

本地使用 Docker Compose 进行部署。

version: "3"  
  
volumes:  
    prometheus_config:  
    prometheus_data:  
    alertmanager_config:  
    grafana_config:  
    grafana_data:  
  
services:  
    prometheus:  
        image: prom/prometheus:v2.20.1  
        container_name: prometheus  
        hostname: prometheus-host  
        ports:  
            - 9090:9090  
        command:  
            - --config.file=/etc/prometheus/prometheus.yml # 指定配置文件  
            - --web.enable-lifecycle # 运行通过 HTTP 接口重新加载配置 (POST localhost:9090/-/reload)  
        volumes:  
            - prometheus_config:/etc/prometheus # 配置  
            - prometheus_data:/prometheus # TSDB、WAL 等数据  
        depends_on:  
            - alertmanager  
  
    alertmanager:  
        image: prom/alertmanager:v0.21.0  
        container_name: alertmanager  
        hostname: alertmanager-host  
        ports:  
            - 9093:9093  
        volumes:  
            - alertmanager_config:/etc/alertmanager # 配置  
  
    # user: admin, psw: admin 
    grafana:  
        image: grafana/grafana:7.1.5  
        container_name: grafana  
        hostname: grafana-host  
        ports:  
            - 3000:3000  
        depends_on:  
            - prometheus  
        volumes:  
            - grafana_config:/etc/grafana # 配置  
            - grafana_data:/var/lib/grafana # DB、Plugins 等数据

样本、时间序列和指标类型

      ^
      │   . . . . . . . . . . . . . . . . . . .   
      │   . . . . . . . . . . . . . . . . . . .   
      │   . . . . . . . . . . . . . . . . . . .
      │   . . . . . . . . . . . . . . . . . . .  
      v
        <------------------ 时间 ---------------->

样本

Prometheus TSDB 存储的基本单位是样本,可以理解为上面坐标中的一个点,横轴代表样本时间,数轴代表样本值。而样本本身又由一系列标签唯一标识,故样本由以下三部分组成:

  • 指标:包含指标名 (指标名称其实也是一个标签) 和描述当前样本特征的标签集 ( labelsets )。
  • 时间戳:一个精确到毫秒的时间戳。
  • 样本值: 一个 float64 的浮点型数据表示当前样本的值。

时间序列

同一指标(指标名和标签集都相同的所有样本)在上面坐标中所构成的一条连续的线,成为一条时间序列。它代表了一个指标在时间范围内的数值波动。

指标类型

为了区分不同类型的指标,Prometheus 抽象出四种类型的指标。

  • Counter 代表一个只增不减的计数器指标,例如,服务接收的请求总量。
  • Gauge 代表一个可增可减的计量器指标,例如,服务内存占用。
上述两种指标都是连续的指标,基于原来的数值进行增减,而下面两种指标属于统计类指标。
  • Histogram 意为直方图,它定义了不同的数值范围(桶),然后将收集到的数据纳入桶内进行计数统计,能够得到不同数值范围之间的比例。
  • Summary 定义了不同的分位点,然后将收集到的数据进行大小排序,最终得到不同分位点对应的数值 (分位数)。

Prometheus server 同时也包含一个 metrics 接口,供自身进行指标采集。在部署之后可以通过 http://your-prometheus-host:9090/metrics 查看到不同指标类型的样本。

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 2.86e-05
go_gc_duration_seconds{quantile="0.25"} 0.0001114
go_gc_duration_seconds{quantile="0.5"} 0.0001812
go_gc_duration_seconds{quantile="0.75"} 0.0003278
go_gc_duration_seconds{quantile="1"} 0.0038698
go_gc_duration_seconds_sum 0.0531145
go_gc_duration_seconds_count 210

上面这部分是 Go 垃圾回收停顿时间的 summary 类型样本,从数据中可以得到如下信息:

  • 总共进行了 210 次垃圾回收。
  • 垃圾回收总耗时 0.0531145。
  • 有一半次数的回收耗时是低于 0.0001812 的。
  • ...

各种指标类型和样本含义不一一说明了,可以细读 文档

PromQL

PromQL 是 Prometheus 的查询语言,可以通过 PromQL 查询单条或多条时间序列,也可以通过 PromQL 内置函数和操作符查询聚合后的数据。

可在 http://your-prometheus-host:9090/new/graph 中输入 PromQL 进行查询。

用法这里不再赘述,请参考 文档

业务中集成 Exporter

我们模拟一个任务队列系统,使用 Go 来编写,用 Channel 来保存任务,利用生产者-消费者模型来进行任务的生产和消费。在生产者每次向队列 Push 任务时,收集队列的堆积的任务数,这是一个 Gauge 类型指标;在消费者处理任务时,统计完成的任务数,这是一个 Counter 指标,同时收集任务的完成时间以统计任务耗时的 Histogram 和 Summary。然后再暴露一个 HTTP 接口提供最新的指标样本数据。

代码在:https://github.com/xvrzhao/examples/tree/master/prometheus

假若该程序是跑在宿主机的,但是我们 Prometheus server 是跑在容器里的,server 要请求宿主机的端口,可以通过主机名 host.docker.internal 与宿主机通信。

可以修改容器里的配置文件 /etc/prometheus/prometheus.yml,增加如下配置:

scrape_configs: 
    - job_name: 'task_queue' 
      static_configs: 
        - targets: ['host.docker.internal:9000']

修改配置后,需要让进程重新加载配置,可以执行如下两种方法:

$ curl -X POST ${Prometheus服务地址}/-/reload
# 或者
$ kill -s HUP ${Prometheus进程PID}

接着就可以在 Prometheus 的 WebUI 查看指标了:
http://your-prometheus-host:9090/new/graph?g0.expr=remain_tasks_in_queue&g0.tab=0&g0.stacked=0&g0.range_input=5m

报警

image.png

报警需要 Prometheus server 和 Alertmanager 配合完成,Prometheus server 只负责评估报警规则条件,如果符合条件则将报警发送给 Alertmanager。

Prometheus server 每次评估时,处于 firing 状态的警报都会发送给 Alertmanager,尽管同一条警报已经发送过一次。所以在 Alertmanager 要做好警报的分组、延迟合并、抑制和静默。关于这些内容,这篇文章讲解 得非常好,这里不再赘述。

对于上面的任务队列系统,我们可以这样配置:

/etc/prometheus/prometheus.yml

global:
 scrape_interval: 15s
 evaluation_interval: 15s

alerting:
 alertmanagers:
 - static_configs:
    - targets:
        - "alertmanager:9093"

rule_files:
 - "/etc/prometheus/rules.yml"

scrape_configs:
 - job_name: 'prometheus'
   static_configs:
    - targets: ['localhost:9090']
 
 - job_name: 'task_queue'
   static_configs:
    - targets: ['host.docker.internal:9000']

/etc/prometheus/rules.yml

groups:
- name: task_queue
  rules:
  - alert: TooManyRemainingTasks
    expr: remain_tasks_in_queue > 30
    for: 1m
    labels:
      severity: warning
    annotations:
      summary: "Too many remaining tasks."
      description: "Current remaining tasks: {{ $value }}"

/etc/alertmanager/alertmanager.yml

global:
 resolve_timeout: 5m
 smtp_smarthost: 'smtp.qq.com:465'
 smtp_from: 'example@qq.com'
 smtp_auth_username: 'example@qq.com'
 smtp_auth_password: 'secret'
 smtp_require_tls: false

route:
 group_by: ['instance']
 group_wait: 1m
 group_interval: 5m
 repeat_interval: 1h
 receiver: 'myemail'

receivers:
- name: 'myemail'
  email_configs: 
  - to: xvrzhao@gmail.com

参考链接


Xavier
448 声望28 粉丝

最近的关注重心: