Exporter详解

初识Prometheus一文中为了采集主机的监控样本数据,我们在主机上安装了一个Node Exporter程序,该程序对外暴露了一个用于获取当前监控样本数据的HTTP访问地址。这样的一个程序称为Exporter,Exporter的实例称为一个Target。Prometheus通过轮询的方式定时从这些Target中获取监控数据样本,并且存储在数据库当中。本文我们将重点讨论这些用于获取特定目标监控样本数据的程序Exporter。

Exporter是什么


广义上讲所有可以向Prometheus提供监控样本数据的程序都可以被称为一个Exporter。而Exporter的一个实例称为Target,如下所示,Prometheus通过轮询的方式定期从这些Target中获取样本数据。

Exporter的来源

从Exporter的来源上来讲,主要分为两类:

社区提供的

Prometheus社区提供了丰富的Exporter实现,涵盖了从基础设施,中间件以及网络等各个方面的监控功能。这些Exporter可以实现大部分通用的监控需求。下表列举了一些社区中常用的Exporter

范围 常用Exporter
数据库 MySQL Exporter, Redis Exporter, MongoDB Exporter, MSSQL Exporter等
硬件 Apcupsd Exporter,IoT Edison Exporter, IPMI Exporter, Node Exporter等
消息队列 Beanstalkd Exporter, Kafka Exporter, NSQ Exporter, RabbitMQ Exporter等
存储 Ceph Exporter, Gluster Exporter, HDFS Exporter, ScaleIO Exporter等
HTTP服务 Apache Exporter, HAProxy Exporter, Nginx Exporter等
API服务 AWS ECS Exporter, Docker Cloud Exporter, Docker Hub Exporter, GitHub Exporter等
日志 Fluentd Exporter, Grok Exporter等
监控系统 Collectd Exporter, Graphite Exporter, InfluxDB Exporter, Nagios Exporter, SNMP Exporter等
其它 Blockbox Exporter, JIRA Exporter, Jenkins Exporter, Confluence Exporter等

用户自定义的

除了直接使用社区提供的Exporter程序以外,用户还可以基于Prometheus提供的Client Library创建自己的Exporter程序,目前Prometheus社区官方提供了对以下编程语言的支持:Go、Java/Scala、Python、Ruby。同时还有第三方实现的如:Bash、C++、Common Lisp、Erlang、Haskeel、Lua、Node.js、PHP、Rust等。

Exporter的运行方式

从Exporter的运行方式上来讲,又可以分为:

独立使用的

以我们已经使用过的Node Exporter为例,由于操作系统本身并不直接支持Prometheus,同时用户也无法通过直接从操作系统层面上提供对Prometheus的支持。因此,用户只能通过独立运行一个程序的方式,通过操作系统提供的相关接口,将系统的运行状态数据转换为可供Prometheus读取的监控数据。除了Node Exporter以外,比如MySQL Exporter、Redis Exporter等都是通过这种方式实现的。这些Exporter程序扮演了一个中间代理人的角色。

集成到应用中的

为了能够更好的监控系统的内部运行状态,有些开源项目如Kubernetes,ETCD等直接在代码中使用了Prometheus的Client Library,提供了对Prometheus的直接支持。这种方式打破了监控的界限,让应用程序可以直接将内部的运行状态暴露给Prometheus,适合于一些需要更多自定义监控指标需求的项目。

Exporter规范

所有的Exporter程序都需要按照Prometheus的规范,返回监控的样本数据。以Node Exporter为例,当访问/metrics地址时会返回以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
# TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 25267.03
node_cpu_seconds_total{cpu="0",mode="iowait"} 1.15
node_cpu_seconds_total{cpu="0",mode="irq"} 0
node_cpu_seconds_total{cpu="0",mode="nice"} 0.01
node_cpu_seconds_total{cpu="0",mode="softirq"} 0.48
node_cpu_seconds_total{cpu="0",mode="steal"} 0
node_cpu_seconds_total{cpu="0",mode="system"} 54.97
node_cpu_seconds_total{cpu="0",mode="user"} 27.06
node_cpu_seconds_total{cpu="1",mode="idle"} 25278.94
node_cpu_seconds_total{cpu="1",mode="iowait"} 3.83
node_cpu_seconds_total{cpu="1",mode="irq"} 0
node_cpu_seconds_total{cpu="1",mode="nice"} 0.02
node_cpu_seconds_total{cpu="1",mode="softirq"} 0.35
node_cpu_seconds_total{cpu="1",mode="steal"} 0
node_cpu_seconds_total{cpu="1",mode="system"} 28.08
node_cpu_seconds_total{cpu="1",mode="user"} 26.41
# HELP node_load1 1m load average.
# TYPE node_load1 gauge
node_load1 0

这是一种基于文本的格式规范,在Prometheus2.0之前的版本还支持Protocol buffer规范。相比于Protocol buffer文本具有更好的可读性,以及跨平台性。Prometheus 2.0的版本也已经不再支持Protocol buffer,这里就不对Protocol buffer规范做详细的阐述。

Exporter返回的样本数据,主要由三个部分组成:样本的一般注释信息(HELP)样本的类型注释信息(TYPE)样本。Prometheus会对Exporter响应的内容逐行解析

如果当前行以# HELP开始,Prometheus将会按照以下规则对内容进行解析,得到当前的指标名称以及相应的说明信息。

1
# HELP <metrics_name> <doc_string>

如果当前行以# TYPE开始,Prometheus会按照以下规则对内容进行解析,得到当前的指标名称以及指标类型

1
# TYPE <metrics_name> <metrics_type>

TYPE注释行必须出现在指标的第一个样本之前。如果没有明确的指标类型需要返回为untyped。 除了# 开头的所有行都会被视为是监控样本数据。 每一行样本需要满足以下格式规范

1
2
3
metric_name [
"{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}"
] value [ timestamp ]

其中metric_namelabel_name必须遵循PromQL的格式规范要求。value是一个float格式的数据,timestamp的类型为int64(从1970-01-01 00:00:00以来的毫秒数),timestamp为可选默认为当前时间。具有相同metric_name的样本必须按照一个组的形式排列,并且每一行必须是唯一的指标名称和标签键值对组合。

需要特别注意的是对于histogram和summary类型的样本。需要按照以下约定返回样本数据

  • 类型为summary或者histogram的指标x,该指标所有样本的值的总和需要使用一个单独的x_sum指标表示。
  • 类型为summary或者histogram的指标x,该指标所有样本的总数需要使用一个单独的x_count指标表示。
  • 对于类型为summary的指标x,其不同分位数quantile所代表的样本,需要使用单独的x{quantile=”y”}表示。
  • 对于类型histogram的指标x为了表示其样本的分布情况,每一个分布需要使用x_bucket{le=”y”}表示,其中y为当前分布的上位数。同时必须包含一个样本x_bucket{le=”+Inf”},并且其样本值必须和x_count相同。
  • 对于histogram和summary的样本,必须按照分位数quantile和分布le的值的递增顺序排序。

以下是类型为histogram和summary的样本输出示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# HELP prometheus_http_request_duration_seconds Histogram of latencies for HTTP requests.
# TYPE prometheus_http_request_duration_seconds histogram
prometheus_http_request_duration_seconds_bucket{handler="/",le="0.1"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="0.2"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="0.4"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="1"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="3"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="8"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="20"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="60"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="120"} 4
prometheus_http_request_duration_seconds_bucket{handler="/",le="+Inf"} 4
prometheus_http_request_duration_seconds_sum{handler="/"} 8.0609e-05
prometheus_http_request_duration_seconds_count{handler="/"} 4

# 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.5629e-05
go_gc_duration_seconds{quantile="0.25"} 7.4967e-05
go_gc_duration_seconds{quantile="0.5"} 0.000138452
go_gc_duration_seconds{quantile="0.75"} 0.000434109
go_gc_duration_seconds{quantile="1"} 0.001976376
go_gc_duration_seconds_sum 0.333584239
go_gc_duration_seconds_count 1264

对于某些Prometheus还没有提供支持的编程语言,用户只需要按照以上规范返回响应的文本数据即可。

指定样本格式的版本

在Exporter响应的HTTP头信息中,可以通过Content-Type指定特定的规范版本,例如:

1
2
3
4
5
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 2906
Content-Type: text/plain; version=0.0.4
Date: Sat, 17 Mar 2018 08:47:06 GMT

其中version用于指定Text-based的格式版本,当没有指定版本的时候,默认使用最新格式规范的版本。同时HTTP响应头还需要指定压缩格式为gzip。

常用Exporter


系统服务监控

监控系统服务运行状态指的是被systemd管理的系统服务都可以使用Prometheus监控起来,可以通过Node Exporter实现(以监控httpd服务和sshd服务为例)

执行node_exporter --help查看node_exporter与systemd相关的参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
--collector.systemd.unit-include=".+"
Regexp of systemd units to include. Units must both match include and not match exclude to be included.
--collector.systemd.unit-exclude=".+\\.(automount|device|mount|scope|slice)"
Regexp of systemd units to exclude. Units must both match include and not match exclude to be included.
--collector.systemd.enable-task-metrics
Enables service unit tasks metrics unit_tasks_current and unit_tasks_max
--collector.systemd.enable-restarts-metrics
Enables service unit metric service_restart_total
--collector.systemd.enable-start-time-metrics
Enables service unit metric unit_start_time_seconds
--collector.systemd Enable the systemd collector (default: disabled).
...

说明
node_exporter v1.2版本之前版本--collector.systemd.unit-include=参数为--collector.systemd.unit-whitelist--collector.systemd.unit-exclude参数为--collector.systemd.unit-blacklist

编辑node_exporter的service文件(例如/usr/lib/systemd/system/node-exporter.service),在ExecStart后添加相关启动参数

1
2
3
4
5
6
[Unit]
Description=node-exporter
After=network.target
[Service]
ExecStart=/usr/local/bin/node_exporter --collector.systemd --collector.systemd.unit-include=(httpd|sshd).service
...

重启node_exporter使配置生效

1
2
systemctl daemon-reload
systemctl restart node-exporter

通过PromQL可以看到已经拉取到node_systemd_unit_state指标的监控数据

容器监控:cAdvisor

Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux/Windows/Mac机器上。容器镜像正成为一个新的标准化软件交付方式。

说明
Docker的安装本文不再赘述,可参考官方文档

例如:可以通过以下命令快速在本地启动一个Nginx服务

1
docker run -itd --restart=always nginx

为了能够获取到Docker容器的运行状态,用户可以通过Docker的stats命令获取到当前主机上运行容器的统计信息,可以查看容器的CPU利用率、内存使用量、网络IO总量以及磁盘IO总量等信息。

1
2
3
# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
ddce09574313 recursing_herschel 1.35% 2.074MiB / 1.791GiB 0.11% 160kB / 348kB 0B / 4.1kB 3

除了使用命令外,用户还可以通过Docker提供的HTTP API查看容器详细的监控统计信息

使用cAdvisor

cAdvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行cAdvisor用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示。

在本地运行cAdvisor也非常简单,直接运行以下命令即可

1
2
3
4
5
6
7
8
9
10
docker run \
--restart=always \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest

通过访问http://IP:8080可以查看当前主机上容器的运行状态,如下所示

cAdvisor是一个简单易用的工具,相比于使用Docker命令行工具,用户不用再登录到服务器中即可以可视化图标的形式查看主机上所有容器的运行状态。

而在多主机的情况下,在所有节点上运行一个cAdvisor再通过各自的UI查看监控信息显然不太方便,同时cAdvisor默认只保存2分钟的监控数据。好消息是cAdvisor已经内置了对Prometheus的支持。访问http://IP:8080/metrics即可获取到标准的Prometheus监控样本输出

下面表格中列举了一些CAdvisor中获取到的典型监控指标

指标名称 类型 含义
container_cpu_load_average_10s gauge 过去10秒容器CPU的平均负载
container_cpu_usage_seconds_total counter 容器在每个CPU内核上的累积占用时间 (单位:秒)
container_cpu_system_seconds_total counter System CPU累积占用时间(单位:秒)
container_cpu_user_seconds_total counter User CPU累积占用时间(单位:秒)
container_fs_usage_bytes gauge 容器中文件系统的使用量(单位:字节)
container_fs_limit_bytes gauge 容器可以使用的文件系统总量(单位:字节)
container_fs_reads_bytes_total counter 容器累积读取数据的总量(单位:字节)
container_fs_writes_bytes_total counter 容器累积写入数据的总量(单位:字节)
container_memory_max_usage_bytes gauge 容器的最大内存使用量(单位:字节)
container_memory_usage_bytes gauge 容器当前的内存使用量(单位:字节)
container_spec_memory_limit_bytes gauge 容器的内存使用量限制
machine_memory_bytes gauge 当前主机的内存总量
container_network_receive_bytes_total counter 容器网络累积接收数据总量(单位:字节)
container_network_transmit_bytes_total counter 容器网络累积传输数据总量(单位:字节)

与Prometheus集成

修改prometheus.yml,将cAdvisor添加监控数据采集任务目标当中

说明
prometheus.yml具体路径视实际环境而定,我的环境在/opt/prometheus/prometheus.yml

1
2
3
4
5
...
# 新增如下部分采集cAdvisor监控数据
- job_name: "cAdvisor"
static_configs:
- targets: ["10.211.55.5:8080"]

重启Prometheus服务

1
systemctl restart prometheus

访问Prometheus的UI,单击“Status”->”Targets“可以看到cAdvisor的Target已经处于UP状态

能够正常采集到cAdvisor的样本数据后,可以通过以下表达式计算容器的CPU使用率

1
sum(irate(container_cpu_usage_seconds_total{image!=""}[1m])) without (cpu)

查询容器内存使用量(单位:字节)

1
container_memory_usage_bytes{image!=""}

查询容器网络接收量速率(单位:字节/秒)

1
sum(rate(container_network_receive_bytes_total{image!=""}[1m])) without (interface)

查询容器网络传输量速率(单位:字节/秒)

1
sum(rate(container_network_transmit_bytes_total{image!=""}[1m])) without (interface)

与Grafana集成

虽然Prometheus已经能够正常采集到cAdvisor的样本数据,但Prometheus UI的图表展示不够直观,因此我们可以通过Grafana来进行图表展示,使得监控数据更加“好看”。

说明
关于Grafana的安装和数据源配置此处不在赘述,可参考初识Prometheus一文

选择"Dashboards"->"Manage"->"Import",输入仪表盘模板ID193,单击"Load"

说明
若环境无法联网,可到https://grafana.com/grafana/dashboards/下载对应仪表盘模板的JSON文件,单击"Upload JSON file"手动导入

设置仪表盘名称,选择数据源为Prometheus,单击"Import"完成仪表盘创建。

说明
仪表盘创建完成后,记得单击右上角的”Save dashboard”按钮进行保存

默认情况下,此模板会将所有节点的cAdvisor数据集中显示,无法区别节点。为了实现选择某一个节点,仪表盘只显示对应节点的监控数据,可对仪表盘进行配置。首先单击仪表盘右上方的"齿轮状按钮(Dashboard settings)"

切换到"Variables"选项卡,单击"Add variable"

配置变量名Name和标签名(仪表盘显示名称)Lable;选择数据源为Prometheus;配置查询语句为label_values(up,instance),查找出所有Targets主机信息;配置正则表达式为.*:8080,只匹配cAdvisor的主机。在页面下方的Preview of values处可查看预览结果,单击"Update",最后单击左侧的"Save dashboard"

此时返回仪表盘页面可以看到已经出现刚才添加的可选择主机的选项,但发现即使选择了其中的一台主机,下方的监控数据仍然没有发生变化,还是展示的所有cAdvisor主机的监控数据。这是因为还需要对监控数据的查询表达式增加筛选条件。以”运行容器数量”为例,单击"Running containers"这个Panel右侧的向下箭头,选择"Edit"

在PromQL查询表达式中增加主机筛选条件,instance="$Node",最后单击右上角的"Apply"即可

说明
仪表盘中所有监控数据项均需按照以上方法增加主机筛选条件

均修改完成后记得单击右上方的”Save dashboard“保存所有配置。

MySQL监控:MySQLD Exporter

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle旗下的产品。 MySQL是最流行的关系型数据库管理系统之一。数据库的稳定运行是保证业务可用性的关键因素之一。可以使用Prometheus提供的MySQLD Exporter实现对MySQL数据库性能以及资源利用率的监控和度量。

说明
MySQL的安装本文不再赘述,可参考官方文档(以MySQL5.7为例)

使用MySQLD Exporter

MySQLD Exporter是官方提供的用于采集MySQL服务器指标的Prometheus Exporter,支持MySQL >= 5.6MariaDB >= 10.2版本(MySQL/MariaDB < 5.6不支持所有的收集方法)。

下载MySQL Exporter后执行如下命令解压到/usr/local/目录下

1
2
tar zxf mysqld_exporter-0.13.0.linux-amd64.tar.gz -C /usr/local/
mv /usr/local/mysqld_exporter-0.13.0.linux-amd64 /usr/local/mysqld_exporter

在要监控的MySQL实例中创建一个用户专门用来给MySQLD Exporter连接数据库使用,并授予PROCESS/REPLICATION CLIENT/SELECT的权限

说明
XXXXXXXX部分为数据库exporter用户密码,可自定义修改

1
2
3
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'XXXXXXXX' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
FLUSH PRIVILEGES;

说明
建议为用户设置最大连接数限制,以避免在重负载情况下使用监视scrapes操作导致服务器过载。并非所有MySQL/MariaDB版本都支持此功能。例如MariaDB的10.1并不支持此功能。

配置my.cnf文件

说明
此处配置的my.cnf文件不建议复用MySQL的/etc/my.cnf文件。除了使用my.cnf文件,还支持通过export DATA_SOURCE_NAME='user:password@(hostname:3306)/'设置环境变量运行

1
2
3
4
5
cat > /usr/local/mysqld_exporter/my.cnf << EOF
[client]
user=exporter
password=XXXXXXXX
EOF

说明
XXXXXXXX部分为数据库exporter用户密码,与上面授权时设置的密码保持一致

配置MySQLD Exporter的service文件

1
2
3
4
5
6
7
8
9
10
11
cat > /usr/lib/systemd/system/mysqld-exporter.service << EOF
[Unit]
Description=mysqld-exporter
[Service]
ExecStart=/usr/local/mysqld_exporter/mysqld_exporter --config.my-cnf=/usr/local/mysqld_exporter/my.cnf
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF

启动MySQLD Exporter

1
2
3
4
systemctl daemon-reload
systemctl enable mysqld-exporter
systemctl start mysqld-exporter
systemctl status mysqld-exporter

访问http://<IP>:9104/metrics即可访问MySQLD Exporter采集并暴露的指标项

与Prometheus集成

修改prometheus.yml,将cAdvisor添加监控数据采集任务目标当中

说明
prometheus.yml具体路径视实际环境而定,我的环境在/opt/prometheus/prometheus.yml

1
2
3
4
5
...
# 新增如下部分采集MySQLD Exporter监控数据
- job_name: "MySQLD Exporter"
static_configs:
- targets: ["10.211.55.5:9104"]

重启Prometheus服务

1
systemctl restart prometheus

访问Prometheus的UI,单击“Status”->”Targets“可以看到MySQLD Exporter的Target已经处于UP状态

与Grafana集成

说明
关于Grafana的安装和数据源配置此处不在赘述,可参考初识Prometheus一文

选择"Dashboards"->"Manage"->"Import",输入仪表盘模板ID7362,单击"Load"

说明
若环境无法联网,可到https://grafana.com/grafana/dashboards/下载对应仪表盘模板的JSON文件,单击"Upload JSON file"手动导入

设置仪表盘名称,选择数据源为Prometheus,单击"Import"完成仪表盘创建。

说明
仪表盘创建完成后,记得单击右上角的”Save dashboard”按钮进行保存

为了确保数据库的稳定运行,通常会关注一下四个与性能和资源利用率相关的指标:吞吐量、连接情况、缓冲池使用情况以及查询执行性能等。

监控数据库吞吐量

对于数据库而言,最重要的工作就是实现对数据的增、删、改、查。为了衡量数据库服务器当前的吞吐量变化情况。在MySQL内部通过一个名为Questions的计数器,当客户端发送一个查询语句后,其值就会+1。可以通过以下MySQL指令查询Questions等服务器状态变量的值:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Questions";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions | 12574 |
+---------------+-------+
1 row in set (0.00 sec)

MySQLD Exporter中返回的样本数据中通过mysql_global_status_questions反映当前Questions计数器的大小:

1
2
3
# HELP mysql_global_status_questions Generic metric from SHOW GLOBAL STATUS.
# TYPE mysql_global_status_questions untyped
mysql_global_status_questions 12644

通过以下PromQL可以查看当前MySQL实例查询速率的变化情况,查询数量的突变往往暗示着可能发生了某些严重的问题,因此用于用户应该关注并且设置响应的告警规则,以及时获取该指标的变化情况:

1
rate(mysql_global_status_questions[2m])

一般还可以从监控读操作和写操作的执行情况进行判断。通过MySQL全局状态中的Com_select可以查询到当前服务器执行查询语句的总次数;相应的,也可以通过Com_insert、Com_update以及Com_delete的总量衡量当前服务器写操作的总次数。例如,可以通过以下指令查询当前MySQL实例select语句的执行次数总量:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Com_select";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_select | 3152 |
+---------------+-------+
1 row in set (0.00 sec)

从MySQLD Exporter的/metrics返回的监控样本中,可以通过mysql_global_status_commands_total获取当前实例各类指令执行的次数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# HELP mysql_global_status_commands_total Total number of executed MySQL commands.
# TYPE mysql_global_status_commands_total counter
mysql_global_status_commands_total{command="admin_commands"} 1187
mysql_global_status_commands_total{command="alter_db"} 0
mysql_global_status_commands_total{command="alter_db_upgrade"} 0
mysql_global_status_commands_total{command="alter_event"} 0
mysql_global_status_commands_total{command="alter_function"} 0
mysql_global_status_commands_total{command="alter_instance"} 0
mysql_global_status_commands_total{command="alter_procedure"} 0
mysql_global_status_commands_total{command="alter_server"} 0
mysql_global_status_commands_total{command="alter_table"} 0
mysql_global_status_commands_total{command="alter_tablespace"} 0
mysql_global_status_commands_total{command="alter_user"} 0
mysql_global_status_commands_total{command="analyze"} 0

用户可以通过以下PromQL查看当前MySQL实例写操作速率的变化情况:

1
sum(rate(mysql_global_status_commands_total{command=~"insert|update|delete"}[2m])) without (command)

连接情况

在MySQL中通过全局设置max_connections限制了当前服务器允许的最大客户端连接数量。一旦可用连接数被用尽,新的客户端连接都会被直接拒绝。 因此当监控MySQL运行状态时,需要时刻关注MySQL服务器的连接情况。用户可以通过以下指令查看当前MySQL服务的max_connections配置:

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'max_connections';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| max_connections | 151 |
+-----------------+-------+
1 row in set (0.00 sec)

MySQL默认的最大链接数为151。临时调整最大连接数,可以通过以下指令进行设置:

1
SET GLOBAL max_connections = 200;

如果想永久化设置,则需要通过修改MySQL配置文件my.cnf,添加以下内容:

1
max_connections = 200

通过Global Status中的Threads_connected、Aborted_connects、Connection_errors_max_connections以及Threads_running可以查看当前MySQL实例的连接情况。

例如,通过以下指令可以直接当前MySQL实例的连接数:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Threads_connected";
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| Threads_connected | 2 |
+-------------------+-------+
1 row in set (0.01 sec)

当所有可用连接都被占用时,如果一个客户端尝试连接至MySQL,会出现“Too many connections(连接数过多)”错误,同时Connection_errors_max_connections的值也会增加。为了防止出现此类情况,你应该监控可用连接的数量,并确保其值保持在max_connections限制以内。同时如果Aborted_connects的数量不断增加时,说明客户端尝试连接到MySQL都失败了。此时可以通过Connection_errors_max_connections以及Connection_errors_internal分析连接失败的问题原因。

下面列举了与MySQL连接相关的监控指标:

  • mysql_global_variables_max_connections: 允许的最大连接数;
  • mysql_global_status_threads_connected: 当前打开的连接的数量;
  • mysql_global_status_threads_running:当前不在睡眠的线程数量(当前并发数);
  • mysql_global_status_aborted_connects:尝试连接到MySQL服务器的失败连接次数;
  • mysql_global_status_connection_errors_total{error=”max_connections”}:由于超出最大连接数导致的错误;
  • mysql_global_status_connection_errors_total{error=”internal”}:由于系统内部导致的错误;

通过PromQL查询当前剩余的可用连接数:

1
mysql_global_variables_max_connections - mysql_global_status_threads_connected

使用PromQL查询当前MySQL实例连接拒绝数:

1
mysql_global_status_aborted_connects

监控缓冲池使用情况

MySQL默认的存储引擎InnoDB使用了一片称为缓冲池的内存区域,用于缓存数据表以及索引的数据。 当缓冲池的资源使用超出限制后,可能会导致数据库性能的下降,同时很多查询命令会直接在磁盘中执行,导致磁盘I/O不断攀升。 因此,应该关注MySQL缓冲池的资源使用情况,并且在合理的时间扩大缓冲池的大小可以优化数据库的性能。

Innodb_buffer_pool_pages_total反映了当前缓冲池中的内存页的总页数。可以通过以下指令查看:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Innodb_buffer_pool_pages_total";
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| Innodb_buffer_pool_pages_total | 8192 |
+--------------------------------+-------+
1 row in set (0.00 sec)

MySQLD Exporter通过以下指标返回缓冲池中各类内存页的数量:

1
2
3
4
5
# HELP mysql_global_status_buffer_pool_pages Innodb buffer pool pages by state.
# TYPE mysql_global_status_buffer_pool_pages gauge
mysql_global_status_buffer_pool_pages{state="data"} 247
mysql_global_status_buffer_pool_pages{state="free"} 7945
mysql_global_status_buffer_pool_pages{state="misc"} 0

Innodb_buffer_pool_read_requests记录了正常从缓冲池读取数据的请求数量。可以通过以下指令查看:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Innodb_buffer_pool_read_requests";
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| Innodb_buffer_pool_read_requests | 1091 |
+----------------------------------+-------+
1 row in set (0.01 sec)

MySQLD Exporter通过以下指标返回缓冲池中Innodb_buffer_pool_read_requests的值:

1
2
3
# HELP mysql_global_status_innodb_buffer_pool_read_requests Generic metric from SHOW GLOBAL STATUS.
# TYPE mysql_global_status_innodb_buffer_pool_read_requests untyped
mysql_global_status_innodb_buffer_pool_read_requests 1091

当缓冲池无法满足时,MySQL只能从磁盘中读取数据。Innodb_buffer_pool_reads即记录了从磁盘读取数据的请求数量。通常来说从内存中读取数据的速度要比从磁盘中读取快很多,因此,如果Innodb_buffer_pool_reads的值开始增加,可能意味着数据库的性能有问题。 可以通过以下只能查看Innodb_buffer_pool_reads的数量

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Innodb_buffer_pool_reads";
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| Innodb_buffer_pool_reads | 214 |
+--------------------------+-------+
1 row in set (0.00 sec)

在MySQLD Exporter中可以通过以下指标查看Innodb_buffer_pool_reads的数量。

1
2
3
# HELP mysql_global_status_innodb_buffer_pool_reads Generic metric from SHOW GLOBAL STATUS.
# TYPE mysql_global_status_innodb_buffer_pool_reads untyped
mysql_global_status_innodb_buffer_pool_reads 214

通过以上监控指标,以及实际监控的场景,我们可以利用PromQL快速建立多个监控项。

通过以下PromQL可以得到各个MySQL实例的缓冲池利用率。一般来说还需要结合Innodb_buffer_pool_reads的增长率情况来结合判断缓冲池大小是否合理:

1
(sum(mysql_global_status_buffer_pool_pages) by (instance) - sum(mysql_global_status_buffer_pool_pages{state="free"}) by (instance)) / sum(mysql_global_status_buffer_pool_pages) by (instance)

也可以通过以下PromQL计算2分钟内磁盘读取请求次数的增长率的变化情况:

1
rate(mysql_global_status_innodb_buffer_pool_reads[2m])

查询性能

MySQL还提供了一个Slow_queries的计数器,当查询的执行时间超过long_query_time的值后,计数器就会+1,其默认值为10秒,可以通过以下指令在MySQL中查询当前long_query_time的设置:

1
2
3
4
5
6
7
mysql> SHOW VARIABLES LIKE 'long_query_time';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)

通过以下指令可以查看当前MySQL实例中Slow_queries的数量:

1
2
3
4
5
6
7
mysql> SHOW GLOBAL STATUS LIKE "Slow_queries";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries | 0 |
+---------------+-------+
1 row in set (0.00 sec)

MySQLD Exporter返回的样本数据中,通过以下指标展示当前的Slow_queries的值:

1
2
3
# HELP mysql_global_status_slow_queries Generic metric from SHOW GLOBAL STATUS.
# TYPE mysql_global_status_slow_queries untyped
mysql_global_status_slow_queries 0

通过监控Slow_queries的增长率,可以反映出当前MySQL服务器的性能状态,可以通过以下PromQL查询Slow_queries的增长情况:

1
rate(mysql_global_status_slow_queries[2m])

在MySQL中还可以通过安装response time插件,从而支持记录查询时间区间的统计信息。启动该功能后MySQLD Exporter也会自动获取到相关数据,从而可以细化MySQL查询响应时间的分布情况。 感兴趣的读者可以自行尝试。

网络探测:Blackbox Exporter

前面主要介绍了Prometheus下如何进行白盒监控,我们监控主机的资源用量、容器的运行状态、数据库中间件的运行数据。 这些都是支持业务和服务的基础设施,通过白盒能够了解其内部的实际运行状态,通过对监控指标的观察能够预判可能出现的问题,从而对潜在的不确定因素进行优化。而从完整的监控逻辑的角度,除了大量的应用白盒监控以外,还应该添加适当的黑盒监控。黑盒监控即以用户的身份测试服务的外部可见性,常见的黑盒监控包括HTTP探针、TCP探针等用于检测站点或者服务的可访问性,以及访问效率等。

黑盒监控相较于白盒监控最大的不同在于黑盒监控是以故障为导向当故障发生时,黑盒监控能快速发现故障,而白盒监控则侧重于主动发现或者预测潜在的问题。一个完善的监控目标是要能够从白盒的角度发现潜在问题,能够在黑盒的角度快速发现已经发生的问题。