4.4 Prometheus 使用指南

本节将介绍监控工具 Prometheus 在 TiDB 中的应用,包括 Prometheus 本身的介绍以及如何通过 Prometheus 查看 TiDB 的监控和利用 Prometheus 的 alertmanager 进行告警。

4.4.1 Prometheus 简介

TiDB 使用开源时序数据库 Prometheus 作为监控和性能指标信息存储方案,使用 Grafana 作为可视化组件进行信息的展示。

Prometheus 狭义上是软件本身,即 prometheus server,广义上是基于 prometheus server 为核心的各类软件工具的生态。除 prometheus server 和 grafana 外,Prometheus 生态常用的组件还有 alertmanager、pushgateway 和非常丰富的各类 exporters。

prometheus server 自身是一个时序数据库,相比使用 MySQL 做为底层存储的 zabbix 监控,拥有非常高效的插入和查询性能,同时数据存储占用的空间也非常小。另外不同于 zabbix,prometheus server 中的数据是从各种数据源主动拉过来的,而不是客户端主动推送的。如果要使用 prometheus server 接收推送的信息,数据源和 prometheus server 中间需要使用 pushgateway。

Prometheus 监控生态非常完善,能监控的对象非常丰富。详细的 exporter 支持对象可参考官方介绍 exporters列表

Prometheus 可以监控的对象远不止官方 exporters 列表中的产品,有些产品原生支持不在上面列表,如 TiDB; 有些可以通过标准的 exporter 来监控一类产品,如 snmp_exporter; 还有些可以通过自己写个简单的脚本往 pushgateway 推送;如果有一定开发能力,还可以通过自己写 exporter 来解决。同时有些产品随着版本的更新,不需要上面列表中的 exporter 就可以支持,比如 ceph。

随着容器和 kurbernetes 的不断落地,以及更多的软件原生支持 Prometheus,相信很快 Prometheus 会成为监控领域的领军产品。

4.4.2 架构介绍

Prometheus 的架构图如下:

1.png

Prometheus 生态中 prometheus server 软件用于监控信息的存储、检索,以及告警消息的推送,是 Prometheus 生态最核心的部分。

Alertmanger 负责接收 prometheus server 推送的告警,并将告警经过分组、去重等处理后,按告警标签内容路由,通过邮件、短信、企业微信、钉钉、webhook 等发送给接收者。

大部分软件在用 Prometheus 作为监控时还需要部署一个 exporter 做为 agent 来采集数据,但是有部分软件原生支持 Prometheus,比如 TiDB 的组件,在不用部署 exporter 的情况下就可以直接采集监控数据。

PromQL 是 Prometheus 数据查询语言,用户可以通过 prometheus server 的 web UI,在浏览器上直接编写 PromQL 来检索监控信息。也可以将 PromQL 固化到 grafana 的报表中做动态的展示,另外用户还可以通过 API 接口做更丰富的自定义功能。

Prometheus 除了可以采集静态的 exporters 之外,还可要通过 service discovery 的方式监控各种动态的目标,如 kubernetes 的 node,pod,service 等。

除 exporter 和 service discovery 之外,用户还可以写脚本做一些自定义的信息采集,然后通过 push 的方式推送到 pushgateway,pushgateway 对于 prometheus server 来说就是一个特殊的 exporter,prometheus server 可以像抓取其他 exporters 一样抓取 pushgateway 的信息。

4.4.3 安装运行

Prometheus 可以运行在 kubernetes 中,也可以运行中虚拟机中。Prometheus 的大部分组件都已经有编译好的二进制文件和 docker 镜像。对于二进制文件,从官方网站下载解压后就可以启动运行,命令如下:

prometheus —config.file=conf/prometheus.yml

建议将二进制文件做成 systemd 的一个服务,这部分可以参考 TiDB 上运行 prometheus 的方式

1. Prometheus server 配置文件

prometheus server 的配置文件是 yaml 格式,由参数 —config.file 指定需要使用的配置文件。配置文件一般命名为 prometheus.yml。

配置文件示例

  1. global:
  2. scrape_interval: 15s
  3. scrape_timeout: 10s
  4. external_labels:
  5. monitor: 'codelab-monitor'
  6. rule_files:
  7. - rules/centos7.rules.yml
  8. - rules/mariadb.rules.yml
  9. alerting:
  10. alertmanagers:
  11. - static_configs:
  12. - targets:
  13. - 21.129.127.3:9093
  14. scrape_configs:
  15. - job_name: 'prometheus'
  16. scrape_interval: 5s
  17. static_configs:
  18. - targets: ['localhost:9090']
  19. - job_name: 'node'
  20. file_sd_configs:
  21. - files:
  22. - conf.d/centos.yml

配置文件说明:

  • global: 指的是全局配置
  • scrape_interval: 抓取目标监控信息的间隔,默认 15 秒
  • scrape_timeout: 抓取时的超时时间,默认 10 秒
  • external_labels: 额外添加的标签,这个标签可以在多个外部系统流转,如:federation, remote storage, Alertmanager
  • rule_files: 这个写的是生成告警规则的配置文件,具体写法见 alertmanger 章节的介绍
  • alerting: 这个是用来配置 alertmanager 地址,可以写多个 alertmanager 的地址
  • scrape_configs: 从这开始,后面是采集对象的配置
  • job_name:可以定义多个 job,每个 job 里有一类的采集对象
  • static_configs: 后面可以写一些静态的监控对象
  • targets: 要抓取的具体对象(instance)
  • file_sd_configs: 如果监控对象过多,可使用这种方式写到独立的文件中

2. 告警规则配置示例

  1. groups:
  2. - name: alert.rules
  3. rules:
  4. - alert: InstanceDown
  5. expr: up == 0
  6. for: 1s
  7. labels:
  8. level: emergency
  9. annotations:
  10. summary: "该实例抓取数据超时"
  11. description: "项目:{{ $labels.project }} , service: {{ $labels.service}}" 当前值{{ $value }}

告警配置说明:

  • groups: 标记当前所有的告警规划为同一组
  • name: 这告警组的自定义名称
  • alert:告警规则的名称
  • expr:告警的表达式
  • for: 问题发生后保持多长时间再推送给 client,调低该值可以提高告警的敏感度,调高会减少告警毛刺
  • labels: 可以加一些自定义的键值对标签
  • annotations: 可以加一些描述信息

4.4.4 Prometheus 在 TiDB 集群中的应用

本节介绍 Promethues 在 TiDB 集群中的应用,主要包括通过 Prometheus PromQL 语言查看 TiDB 的监控,以及告警配置的讲解。

1. TiDB 集群中 Prometheus 的部署架构

TiDB 已经原生支持 Prometheus,在 2.1 之前的版本,TiDB 的监控信息是由各 TiDB 的各个组件主动上报给 pushgateway,再由 prometheus server 去 pushgateway 上主动抓取监控信息。从 2.1 版本开始,TiDB 暴露 Metrics 接口 ,由 prometheus server 主动抓取信息,这样的架构更符合 Prometheus 的设计思想,整个数据采集路径少了一层 pushgateway。数据采集完成后由 grafana 做报表展示,同时告警信息主动推送给 alertmanager,再由 altermanager 将告警推送到不同的消息渠道。

2.png

2. 通过 Prometheus PromQL 语言查看 TiDB 的监控

PromQL(Prometheus Query Language) 是 Promehteus 提供的函数查询语言,可以进行实时查询,也可以通过函数做聚合运算。本节介绍下如何通过 PromQL 对 TiDB 的监控信息进行查询。

(1) 数据类型

Promethes 中的数据类型分 4 类:

  • Instant vector - 一个时间点的时序数据;
  • Range vector - 一个时间段的时序数据;
  • Scalar - 数字,浮点值;
  • String - 字符串,当前还没有用。

(2) 通过 web UI 执行查询

下图是在 web UI (http://prometheus-server:9090/graph) 上执行 up{instance=”21.129.14.103:2998”} 表达式查询到的某个实例的存活状态。

3.png

(3) 结果中各个字段的意义:

  • up: 是一条具体的时序记录名字,同时 up 又是一条特殊的时序名称,他是 Prometheus 对每个监控对象自动生成的,指示该对象的起停状态,1 表示可连通,0 表示不可能连通(注意,0 不一定是服务挂了,也有可能是获取记录的时候超时了)。
  • 表达式中的 instance, job, project, service, alert_lev 都是该条的记录的标签,相对于关系型数据库中的字段。其中 instance 和 job 是基于 prometheus.yaml 中的内容自动生成的,project, service, alert_lev 是用户自定义的标签。instance 一般是 prometheus 里的 target,但是也可以在标签里重写。
  • 最后的 1 是这条记录在查询时的结果。

3. Instant vector 查询

下面列举下几种 Instant vector 查询的常见用法:

  • 直接写时序名称,例如: server_query_total
  • 在 {} 中加一些标签作为过滤条件,例如: server_query_total{job=”tikv”}
  • 一个标签匹配多个值,例如: server_query_total{job=~”tikv|tidb”}
  • 指定需要过滤掉值,例如: server_query_total{job!~”tikv|pd”}
  • 匹配正则表达式,例如: up{tidb=~”.+”},可以匹配所以包含 tidb 的 up 时序数据
  • 使用算术运算和比较运算过滤结果: tikv_engine_bytes_written{instance=”21.129.14.104:21910”}/1024/1024 > 500

4. Range vector 查询

Range vector 查询类似于 instance vector 查询,不同之处在于通过 [] 加上时间范围限制,时间单位可以设置为:

  • s - seconds
  • m - minutes
  • h - hours
  • d - days
  • w - weeks
  • y - years

下面看看监控 TiDB QPS 的例子,展示的是 172.16.4.51:10080 这台 TiDB 实例的 QPS 情况:

4.png

5. offset 查询

通过 offset 能够查询过去某个时间点的监控结果,如下查询的是一天前 TiDB 的请求数总量:

sum((tidb_server_query_total{result=”OK”} offset 1d))

4.4.5 TiDB 监控中常用函数

本节结合实际例子,介绍下 TiDB 监控中经常用到的一些函数。

rate 和 irate

这两个函数一般作用于计数器 counter 类型的数据,这类数据会一直增加,使用这两个函数后,展示的是一定时间范围内的变化情况。但它俩的计算方式是有差异,irate() 是基于时间范围内连续的两个时间点,而 rate() 是基于时间范围内的所有时间点,所以 irate() 展示的数据更为精确些,做图毛刺也会更明显。下图展示的是 TiDB 集群中节点的 CPU 使用率的监控,对应的表达式是 rate(process_cpu_seconds_total{job=”tidb”}[1m])。

5.png

sum 和 avg

sum 是求和函数,avg 是求均值函数。表达式 sum(tikv_store_size_bytes{instance=~”$instance”}) by (instance) 查询的是各个 TiKV 实例的容量总和。

6.png

increase

increase 函数计算的是指定时间范围内的变化量,例如表达式 sum(increase(tidb_server_execute_error_total[1m])) by (type) 是以 type 为聚合条件,显示 1 分钟内 Failed Query OPM 总数

7.png

histogram_quantile

histogram_quantile 是累积直方图百分位函数,用法 histogram_quantile(φ float, b instant-vector),其中百分位 φ 是介于 0 和 1 之间的值。这个函数计算的结果是直方图中指定百分比的最大值,例如 0.95 的百分位的结果是 200,说明所有数据中,小于 200 的占总数据的比例为 95%。下面表达式是展示各个 tidb-server 请求的 99% 延迟情况。

histogram_quantile(0.99, sum(rate(tidb_server_handle_query_duration_seconds_bucket[1m])) by (le, instance))

8.png

4.4.6 通过配置 alertmanager 对 TiDB 故障进行报警

本节介绍下 TiDB 中是如何配置 Promethues 的报警的。如果是通过 tidb-ansible 方式部署的集群,Promethues 的报警配置文件对应的路径是 tidb-ansbile/roles/prometheus/files/tidb.rules.yml。

1. TiDB 告警级别

TiDB 组件的报警项,根据严重级别可分为三类,按照严重程度由高到低依次为:紧急级别、重要级别、警告级别。

紧急级别报警项

紧急级别的报警通常由于服务停止或节点故障导致,此时需要马上进行人工干预操作。告警规则里的标签 level: emergency。下面展示的是 TiDB_schema_error 的告警示例:TiDB 在一个 Lease 时间内没有重载到最新的 Schema 信息,导致 TiDB 无法继续对外提供服务,需要报警。该问题通常由于 TiKV Region 不可用或超时导致,需要看 TiKV 的监控指标定位问题,比如确认 TiKV 实例是否还存活着。

  1. - alert: TiDB_schema_error
  2. expr: increase(tidb_session_schema_lease_error_total{type="outdated"}[15m]) > 0
  3. for: 1m
  4. labels:
  5. env: ENV_LABELS_ENV
  6. level: emergency
  7. expr: increase(tidb_session_schema_lease_error_total{type="outdated"}[15m]) > 0
  8. annotations:
  9. description: 'cluster: ENV_LABELS_ENV, instance: {{ $labels.instance }}, values:{{ $value }}'
  10. value: '{{ $value }}'
  11. summary: TiDB schema error

重要级别报警项

对于重要级别的报警,需要密切关注异常的指标。告警规则里的标签 level: critical。下面示例展示的是 tidb-server 进程发生崩溃的时候进行报警。收到该报警的一般处理方式是收集 TiDB 的 panic 日志,定位 panic 的原因,比如是否是 tidb-server 实例 OOM 导致的问题。

  1. - alert: TiDB_server_panic_total
  2. expr: increase(tidb_server_panic_total[10m]) > 0
  3. for: 1m
  4. labels:
  5. env: ENV_LABELS_ENV
  6. level: critical
  7. expr: increase(tidb_server_panic_total[10m]) > 0
  8. annotations:
  9. description: 'cluster: ENV_LABELS_ENV, instance: {{ $labels.instance }}, values:{{ $value }}'
  10. value: '{{ $value }}'
  11. summary: TiDB server panic total

警告级别报警项

警告级别的报警是对某一问题或错误的提醒。告警规则里的标签 level: warning。下面展示的是对于 tidb-server 实例内存异常的报警,当 tidb-server 实例的内存占用大于 10GB 的时候进行报警。收到该报警的时候,需要注意是否有大查询在执行,比如大表的 Join 查询。

  1. - alert: TiDB_memory_abnormal
  2. expr: go_memstats_heap_inuse_bytes{job="tidb"} > 1e+10
  3. for: 1m
  4. labels:
  5. env: ENV_LABELS_ENV
  6. level: warning
  7. expr: go_memstats_heap_inuse_bytes{job="tidb"} > 1e+10
  8. annotations:
  9. description: 'cluster: ENV_LABELS_ENV, instance: {{ $labels.instance }}, values:{{ $value }}'
  10. value: '{{ $value }}'
  11. summary: TiDB heap memory usage is over 10 GB

更多关于 TiDB 报警规划,以及 TiDB 详细告警的处理方法,请参考 官网介绍

2. 为 TiDB 集群配置 alertmanager 告警路由

由于往外发送告警需要邮箱、短信、企业微信等外部消息通道打通,一般企业内部都有各自不同的安全要求和操作规范。另外像短信接口并不是统一标准的,大部分也不是原生支持 Prometheus 的,所以需要用户自己编写适配脚本,以 webhook 的方式与 alertmanger 进行适配。

建议使用 TiDB 时,用户自己创建一个独立的 alertmanager,用于接收来自不同 prometheus server 的告警,统一集中路由发送,既可以有效安全管理,也可以减少用户自己的部署操作。如果用户采用的是 tidb-ansible 方式部署的 TiDB 集群,alertmanager 的配置文件位于 tidb-ansible/conf/alertmanager.yml。

告警路由配置

  1. routes:
  2. - match:
  3. env: test-cluster
  4. level: emergency
  5. receiver: tidb-emergency
  6. group_by: [alertname, cluster, service]

下面简单解释下各个字段的含义:

  • match 是一条路由规划。
  • env 和 level 是从 Prometheus 发送过来的记录所携带的标签,如果能够匹配该标签,则符合当前这条路由规则。
  • receiver 表示接收人,和后面接收部分的 name 一致。
  • group_by 里面的内容是分组聚合的标签。

告警接收配置

  1. receivers:
  2. - name: 'tidb-emergency'
  3. webhook_configs:
  4. - url: 'xxxx'
  5. wechat_configs:
  6. - corp_id: 'xxxxx'
  7. to_party: 'xxx'
  8. agent_id: 'xxxx'
  9. api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
  10. api_secret: 'xxxxxx'
  • name:和上面路由规则的 receiver 对应。
  • webhook_configs:以 webhook 的方式发送。
  • wechat_configs:以企业微信的方式发送,具体要求参考 企业微信 文档;
  • 由于默认的告警发送的内容过多,包含注释等信息,影响可读性。建议用户自己写 webhook 的方式发送告警。