Prometheus 完全指南 / 11 - Exporter 生态
11 - Exporter 生态
11.1 概述
Exporter 是 Prometheus 生态的核心组件之一,负责将第三方系统的指标转换为 Prometheus 可抓取的格式(/metrics 端点)。
工作原理
┌──────────┐ ┌──────────────┐ ┌──────────────┐
│ 第三方系统 │◄──────►│ Exporter │◄──────►│ Prometheus │
│ (MySQL等) │ 查询 │ /metrics │ 抓取 │ Server │
└──────────┘ └──────────────┘ └──────────────┘
1. Exporter 连接第三方系统
2. 查询/收集指标数据
3. 转换为 Prometheus 格式
4. 暴露 /metrics 端点
5. Prometheus 定期抓取
常用 Exporter
| Exporter | 用途 | 默认端口 |
|---|
| Node Exporter | 系统/硬件指标 | 9100 |
| MySQL Exporter | MySQL 数据库 | 9104 |
| Redis Exporter | Redis 缓存 | 9121 |
| MongoDB Exporter | MongoDB | 9216 |
| Blackbox Exporter | 黑盒探针 | 9115 |
| Nginx Exporter | Nginx | 9113 |
| Kafka Exporter | Kafka | 9308 |
| Elasticsearch Exporter | Elasticsearch | 9114 |
| RabbitMQ Exporter | RabbitMQ | 9419 |
| PostgreSQL Exporter | PostgreSQL | 9187 |
11.2 Node Exporter
Node Exporter 是最基础也是最常用的 Exporter,用于收集系统级指标。
安装
# 二进制安装
NODE_EXPORTER_VERSION="1.7.0"
wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xvfz node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
sudo cp node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter /usr/local/bin/
# Docker
docker run -d \
--name=node-exporter \
--net=host \
--pid=host \
-v "/:/host:ro,rslave" \
prom/node-exporter:v1.7.0 \
--path.rootfs=/host
Systemd 服务
# /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
After=network.target
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd \
--collector.processes \
--web.listen-address=:9100
Restart=always
[Install]
WantedBy=multi-user.target
主要指标
| 指标 | 说明 |
|---|
node_cpu_seconds_total | CPU 使用时间 |
node_memory_MemTotal_bytes | 总内存 |
node_memory_MemAvailable_bytes | 可用内存 |
node_filesystem_size_bytes | 文件系统总大小 |
node_filesystem_avail_bytes | 文件系统可用空间 |
node_network_receive_bytes_total | 网络接收字节数 |
node_disk_io_time_seconds_total | 磁盘 IO 时间 |
node_load1/5/15 | 系统负载 |
node_boot_time_seconds | 系统启动时间 |
node_time_seconds | 当前时间 |
常用 Collector
| Collector | 默认 | 说明 |
|---|
| cpu | ✅ | CPU 指标 |
| diskstats | ✅ | 磁盘统计 |
| filesystem | ✅ | 文件系统 |
| loadavg | ✅ | 系统负载 |
| meminfo | ✅ | 内存信息 |
| netdev | ✅ | 网络设备 |
| systemd | ❌ | systemd 服务状态 |
| processes | ❌ | 进程信息 |
| hwmon | ✅ | 硬件传感器 |
# 启用特定 collector
node_exporter \
--collector.systemd \
--collector.processes \
--no-collector.wifi \
--no-collector.infiniband
11.3 MySQL Exporter
安装与配置
# 安装
MYSQL_EXPORTER_VERSION="0.15.1"
wget https://github.com/prometheus/mysqld_exporter/releases/download/v${MYSQL_EXPORTER_VERSION}/mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xvfz mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64.tar.gz
sudo cp mysqld_exporter-${MYSQL_EXPORTER_VERSION}.linux-amd64/mysqld_exporter /usr/local/bin/
创建 MySQL 用户
-- 创建监控专用用户
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'password';
-- 授予权限
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
FLUSH PRIVILEGES;
配置文件
# /etc/.mysqld_exporter.cnf
[client]
user=exporter
password=password
host=localhost
port=3306
启动
mysqld_exporter \
--config.my-cnf=/etc/.mysqld_exporter.cnf \
--collect.info_schema.processlist \
--collect.info_schema.innodb_metrics \
--collect.global_status \
--collect.global_variables \
--collect.slave_status \
--collect.engine_innodb_status
主要指标
| 指标 | 说明 |
|---|
mysql_up | MySQL 是否可达 |
mysql_global_status_threads_connected | 当前连接数 |
mysql_global_status_threads_running | 活跃线程数 |
mysql_global_status_queries | 查询总数 |
mysql_global_status_slow_queries | 慢查询总数 |
mysql_global_status_questions | 问题总数 |
mysql_global_status_innodb_buffer_pool_reads | InnoDB 缓冲池读取 |
mysql_info_schema_processlist_count | 进程列表 |
11.4 Redis Exporter
安装与启动
# 安装
REDIS_EXPORTER_VERSION="1.58.0"
wget https://github.com/oliver006/redis_exporter/releases/download/v${REDIS_EXPORTER_VERSION}/redis_exporter-v${REDIS_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xvfz redis_exporter-v${REDIS_EXPORTER_VERSION}.linux-amd64.tar.gz
sudo cp redis_exporter /usr/local/bin/
# 启动
redis_exporter \
--redis.addr=redis://localhost:6379 \
--redis.password=password \
--web.listen-address=:9121
# Docker
docker run -d \
--name=redis-exporter \
-p 9121:9121 \
oliver006/redis_exporter:v1.58.0 \
--redis.addr=redis://redis:6379
主要指标
| 指标 | 说明 |
|---|
redis_up | Redis 是否可达 |
redis_connected_clients | 连接客户端数 |
redis_used_memory_bytes | 使用内存 |
redis_memory_max_bytes | 最大内存限制 |
redis_commands_processed_total | 命令处理总数 |
redis_keyspace_hits_total | 缓存命中 |
redis_keyspace_misses_total | 缓存未命中 |
redis_connected_slaves | 从节点数 |
常用查询
# 缓存命中率
redis_keyspace_hits_total / (redis_keyspace_hits_total + redis_keyspace_misses_total)
# 内存使用率
redis_used_memory_bytes / redis_memory_max_bytes
# 每秒命令处理数
rate(redis_commands_processed_total[5m])
11.5 Blackbox Exporter
Blackbox Exporter 通过 HTTP、TCP、ICMP、DNS 等协议探测目标的可用性。
配置文件
# /etc/blackbox_exporter/config.yml
modules:
http_2xx:
prober: http
timeout: 5s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 301, 302]
method: GET
follow_redirects: true
preferred_ip_protocol: "ip4"
tls_config:
insecure_skip_verify: false
http_post_2xx:
prober: http
http:
method: POST
valid_status_codes: [200, 201]
tcp_connect:
prober: tcp
timeout: 5s
icmp:
prober: icmp
timeout: 5s
dns_resolve:
prober: dns
dns:
query_name: "example.com"
query_type: "A"
valid_rcodes: ["NOERROR"]
启动
blackbox_exporter \
--config.file=/etc/blackbox_exporter/config.yml \
--web.listen-address=:9115
Prometheus 配置
scrape_configs:
# HTTP 探测
- job_name: 'blackbox-http'
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://example.com
- https://api.example.com/health
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox:9115
# ICMP 探测
- job_name: 'blackbox-icmp'
metrics_path: /probe
params:
module: [icmp]
static_configs:
- targets:
- 10.0.0.1
- 10.0.0.2
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox:9115
# TCP 探测
- job_name: 'blackbox-tcp'
metrics_path: /probe
params:
module: [tcp_connect]
static_configs:
- targets:
- mysql:3306
- redis:6379
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: blackbox:9115
主要指标
| 指标 | 说明 |
|---|
probe_success | 探测是否成功 (1/0) |
probe_duration_seconds | 探测耗时 |
probe_http_status_code | HTTP 状态码 |
probe_http_duration_seconds | HTTP 各阶段耗时 |
probe_dns_lookup_time_seconds | DNS 解析时间 |
probe_icmp_duration_seconds | ICMP 耗时 |
11.6 自定义 Exporter
Go 实现
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var (
// 定义指标
ordersTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: "business",
Subsystem: "orders",
Name: "created_total",
Help: "Total number of orders created",
},
[]string{"channel", "status"},
)
orderAmount = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Namespace: "business",
Subsystem: "orders",
Name: "amount_cents",
Help: "Order amount in cents",
Buckets: []float64{100, 500, 1000, 5000, 10000, 50000, 100000},
},
[]string{"channel"},
)
queueLength = prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: "business",
Subsystem: "orders",
Name: "queue_length",
Help: "Current order processing queue length",
},
[]string{"queue"},
)
)
func init() {
prometheus.MustRegister(ordersTotal, orderAmount, queueLength)
}
func main() {
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":9200", nil)
}
Python 实现
from prometheus_client import start_http_server, Counter, Gauge, Histogram
import time
import psutil
# 定义指标
CPU_TEMP = Gauge('hardware_cpu_temperature_celsius', 'CPU temperature')
DISK_IO = Counter('hardware_disk_reads_total', 'Total disk reads', ['device'])
REQUEST_LATENCY = Histogram(
'custom_request_duration_seconds',
'Request latency',
buckets=[0.01, 0.05, 0.1, 0.5, 1, 5]
)
def collect_metrics():
"""定期采集指标"""
while True:
# CPU 温度
temps = psutil.sensors_temperatures()
if 'coretemp' in temps:
CPU_TEMP.set(temps['coretemp'][0].current)
# 磁盘 IO
io = psutil.disk_io_counters()
DISK_IO.labels(device='sda')._value.set(io.read_count)
time.sleep(15)
if __name__ == '__main__':
start_http_server(9200)
collect_metrics()
11.7 Exporter 最佳实践
| 实践 | 说明 |
|---|
| 使用官方 Exporter | 优先选择 Prometheus 官方维护的 Exporter |
| 合理设置采集间隔 | Exporter 系统的采集间隔应与 Prometheus 抓取间隔匹配 |
| 限制标签基数 | 避免 Exporter 产生高基数标签 |
| 独立部署 | Exporter 应与被监控系统部署在同一主机 |
| 资源限制 | 为 Exporter 设置 CPU/内存限制 |
| 超时配置 | 设置合理的抓取超时 |
11.8 本章小结
| Exporter | 用途 | 默认端口 |
|---|
| Node Exporter | 系统指标 | 9100 |
| MySQL Exporter | MySQL | 9104 |
| Redis Exporter | Redis | 9121 |
| Blackbox Exporter | 探针 | 9115 |
| 自定义 Exporter | 业务指标 | 自定义 |
扩展阅读
上一章:10 - 服务发现
下一章:12 - Pushgateway