2. Exporter基础:Prometheus Exporter的工作原理、注册与暴露指标、典型Exporter架构

2.1 核心工作原理

Prometheus Exporter 是一个适配器程序,负责将非 Prometheus 原生格式的监控数据转换为 Prometheus 能够抓取的指标格式。其核心是一个 HTTP 服务端,在 /metrics 端点暴露符合 Prometheus 文本格式的指标数据。

核心工作流: 采集目标状态 → 调用目标API/命令 → 解析数据 → 构造指标对象 → 注册到Registry → HTTP Handler响应GET请求 → 返回文本格式指标。
Exporter 核心工作流 采集目标状态 调用API/命令 解析数据 构造指标对象 注册到Registry HTTP Handler GET /metrics 返回文本指标 说明: Prometheus Server 定期向 Exporter 的 /metrics 端点发起 HTTP GET 请求,Exporter 返回当前采集到的所有指标快照。 每次抓取都是独立的,Exporter 不维护抓取状态,只负责提供最新数据。

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服务提供抓取端点。

典型 Exporter 三层架构 采集器层 (Collector) 系统调用采集器 API采集器 文件解析采集器 DB查询采集器 注册表层 (Registry) 默认Registry 自定义Registry 指标描述注册 Gatherer HTTP服务层 (Handler) /metrics 端点 promhttp.Handler() 文本格式序列化

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 生态的标准数据交换格式。