2. Exporter基础:Prometheus Exporter的工作原理、注册与暴露指标、典型Exporter架构
2.1 核心工作原理
Prometheus Exporter 是一个适配器程序,负责将非 Prometheus 原生格式的监控数据转换为 Prometheus 能够抓取的指标格式。其核心是一个 HTTP 服务端,在 /metrics 端点暴露符合 Prometheus 文本格式的指标数据。
核心工作流: 采集目标状态 → 调用目标API/命令 → 解析数据 → 构造指标对象 → 注册到Registry → HTTP Handler响应GET请求 → 返回文本格式指标。
2.2 指标注册与暴露机制
Prometheus 客户端库提供了一套完整的指标注册体系。所有指标必须先注册到 Registry(注册表),然后通过 HTTP Handler 统一暴露。
2.2.1 指标类型与注册方式
| 指标类型 | Go客户端结构体 | 注册方法 | 典型用途 |
|---|---|---|---|
| Counter | prometheus.NewCounter |
prometheus.MustRegister() |
请求总数、错误总数 |
| Gauge | prometheus.NewGauge |
prometheus.MustRegister() |
当前连接数、温度、内存使用量 |
| Histogram | prometheus.NewHistogram |
prometheus.MustRegister() |
请求延迟分布、响应大小分布 |
| Summary | prometheus.NewSummary |
prometheus.MustRegister() |
分位数延迟(如p99) |
2.2.2 代码示例:注册与暴露
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
// 定义指标
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests.",
},
[]string{"method", "endpoint"},
)
cpuTemperature = prometheus.NewGauge(
prometheus.GaugeOpts{
Name: "cpu_temperature_celsius",
Help: "Current CPU temperature in Celsius.",
},
)
)
func init() {
// 注册指标到默认Registry
prometheus.MustRegister(httpRequestsTotal)
prometheus.MustRegister(cpuTemperature)
}
func main() {
// 模拟指标更新
httpRequestsTotal.WithLabelValues("GET", "/api/v1/status").Inc()
cpuTemperature.Set(65.3)
// 暴露 /metrics 端点
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
}
最佳实践: 使用
prometheus.MustRegister() 在 init() 函数中注册指标,确保程序启动时指标就已就绪。自定义 Registry 适用于需要隔离指标命名空间的场景。
2.3 典型Exporter架构
生产级 Exporter 通常采用 采集器(Collector) + 注册表(Registry) + HTTP服务 的三层架构。采集器负责与目标系统交互,注册表管理指标生命周期,HTTP服务提供抓取端点。
2.3.1 架构组件职责
| 层级 | 组件 | 职责 | 故障排查关注点 |
|---|---|---|---|
| 采集器 | Collector 接口实现 | 执行采集逻辑,返回指标切片 | 采集超时、目标不可达、数据解析异常 |
| 注册表 | Registry / Gatherer | 管理指标注册,收集所有指标 | 指标冲突、重复注册、未注册指标 |
| HTTP服务 | promhttp.Handler | 响应抓取请求,序列化指标 | 端口冲突、TLS配置、压缩问题 |
2.4 采集器(Collector)接口详解
Prometheus 客户端库定义了 Collector 接口,所有自定义采集器都必须实现该接口:
// Collector 接口定义
type Collector interface {
Describe(chan<- *prometheus.Desc)
Collect(chan<- prometheus.Metric)
}
- Describe:向 channel 发送指标描述信息,用于注册时的元数据校验。
- Collect:执行实际采集,向 channel 发送当前指标值。每次抓取都会调用一次。
常见故障点: Describe 和 Collect 必须保持一致的指标描述。如果 Describe 发送了 3 个指标描述,但 Collect 只发送了 2 个指标值,Prometheus 会报错 "collected metric ... was collected before with the same name and label values"。
2.5 典型Exporter示例:node_exporter 架构
以 node_exporter 为例,其架构是 Exporter 设计模式的经典实现:
| 组件 | 实现方式 | 说明 |
|---|---|---|
| 主程序 | main.go |
解析命令行参数,启动HTTP服务 |
| 采集器管理器 | collector/manager.go |
管理所有采集器的启用/禁用 |
| 各采集器 | collector/cpu.go, collector/memory.go 等 |
每个文件实现一个独立的采集器,读取 /proc 或 /sys 文件 |
| 指标注册 | prometheus.NewRegistry() |
使用自定义 Registry,避免与默认 Registry 冲突 |
| HTTP端点 | promhttp.HandlerFor(registry, ...) |
为自定义 Registry 创建 Handler |
架构启示: 每个采集器独立实现 Collector 接口,通过管理器统一注册。这种设计使得新增采集器只需添加新文件,无需修改主流程,便于扩展和维护。
2.6 指标暴露格式
Prometheus Exporter 暴露的指标遵循 Prometheus 文本格式,示例如下:
# HELP http_requests_total Total number of HTTP requests.
# TYPE http_requests_total counter
http_requests_total{method="GET",endpoint="/api/v1/status"} 1024
http_requests_total{method="POST",endpoint="/api/v1/data"} 512
# HELP cpu_temperature_celsius Current CPU temperature in Celsius.
# TYPE cpu_temperature_celsius gauge
cpu_temperature_celsius 65.3
# HELP http_request_duration_seconds HTTP request latency in seconds.
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 100
http_request_duration_seconds_bucket{le="0.5"} 300
http_request_duration_seconds_bucket{le="1.0"} 450
http_request_duration_seconds_bucket{le="+Inf"} 500
http_request_duration_seconds_sum 150.0
http_request_duration_seconds_count 500
格式要点:
# HELP和# TYPE是注释行,帮助文档和类型声明。- 指标名和标签名遵循
[a-zA-Z_:][a-zA-Z0-9_:]*正则。 - 标签值如果包含特殊字符(如引号、换行),需要转义。
- Histogram 和 Summary 类型会暴露多个时间序列(_bucket、_sum、_count)。
2.7 本章小结
- 工作原理:Exporter 作为适配器,将目标系统数据转换为 Prometheus 指标格式,通过 HTTP 端点暴露。
- 注册与暴露:指标通过 Registry 注册,使用
promhttp.Handler()在/metrics端点暴露。 - 典型架构:采集器(Collector) + 注册表(Registry) + HTTP服务(Handler) 三层架构,各层职责清晰。
- Collector接口:
Describe和Collect方法必须一致,否则会导致抓取错误。 - 文本格式:HELP/TYPE 注释 + 指标行 + 标签,是 Prometheus 生态的标准数据交换格式。