2. Metric 类型与采集:Counter、Gauge、Histogram、Summary 的区别与适用场景,Prometheus Exporter 采集原理

2.1 四大核心 Metric 类型

Prometheus 定义了四种核心 Metric 类型,每种类型对应不同的数据特征与查询模式。理解它们的差异是设计可靠告警与容量水位阈值的前提。

类型语义值特征典型场景查询函数
Counter只增不减的累计计数器单调递增,重启归零请求总数、错误总数、CPU 时间rate()、increase()
Gauge可增可减的瞬时值上下波动,反映当前状态内存使用量、连接数、温度avg()、max()、min()
Histogram分桶统计的分布直方图多个 bucket 计数器 + 总和 + 计数请求延迟分布、响应大小分布histogram_quantile()
Summary预计算的分位数摘要客户端侧计算 φ 分位数 + 总和 + 计数SLI 延迟分位数(0.5/0.9/0.99)直接读取 _quantile 标签
关键原则:Counter 必须配合 rate() 或 increase() 使用,直接对 Counter 做值告警几乎总是错误的;Gauge 适合设置静态阈值;Histogram 与 Summary 都用于延迟分析,但 Histogram 支持服务端动态聚合,Summary 则无法跨实例聚合。

2.2 类型选择决策树

在实际 Metric 设计时,按以下顺序判断应使用哪种类型:

  1. 数据是否只增不减? → 是 → Counter(请求量、错误量、写入字节数)
  2. 数据是否可增可减,反映当前状态? → 是 → Gauge(内存、连接数、队列深度)
  3. 是否需要分析分布或计算分位数? → 是
  4. 是否需要跨实例聚合分位数? → 是 → Histogram(服务端聚合)
  5. 是否已知固定分位数且无需跨实例聚合? → 是 → Summary(客户端预计算)
Metric 类型选择决策流程 数据特征分析 只增不减? Counter 可增可减? Gauge 需要分布分析? 跨实例聚合? Histogram Summary

2.3 Histogram 与 Summary 的深层对比

Histogram 和 Summary 都用于度量延迟分布,但架构差异显著,直接影响容量压测时的水位口径选择。

维度HistogramSummary
分位数计算位置服务端(Prometheus Server)客户端(Exporter 内)
聚合能力支持跨实例 histogram_quantile() 聚合不支持聚合,只能查看单实例
存储开销由 bucket 数量决定(通常 10~15 个)由分位数数量决定(通常 3~5 个)
精度控制受 bucket 边界影响,边界内线性插值客户端精确计算,无插值误差
适用场景全局延迟 SLO、多实例聚合告警单实例精确分位数、固定分位数需求
容量压测建议:在压测水位评估中优先使用 Histogram,因为它允许在压测结束后通过调整 bucket 边界重新计算分位数,无需重新采集数据。Summary 一旦采集,分位数即固定,无法回溯调整。

2.4 Prometheus Exporter 采集原理

Exporter 是 Prometheus 生态中负责将第三方系统指标转换为 Prometheus 可抓取格式的代理组件。其核心采集流程如下:

  1. 注册 Metric 描述符:在 Exporter 初始化时,通过 prometheus.NewCounterVec()、prometheus.NewGaugeVec() 等函数定义 Metric 的名称、标签、帮助信息。
  2. 采集器(Collector)实现:实现 prometheus.Collector 接口的 Describe() 和 Collect() 方法。Describe() 发送 Metric 描述,Collect() 发送当前样本值。
  3. HTTP Handler 暴露:通过 promhttp.Handler() 将采集到的 Metric 序列化为 Prometheus 文本格式,在 /metrics 端点暴露。
  4. 抓取与拉取模型:Prometheus Server 定期向 Exporter 的 /metrics 发起 HTTP GET 请求,拉取文本数据并解析入库。
Prometheus Exporter 采集架构 被监控系统 (MySQL / Nginx / JVM) Exporter 进程 Collect() → 序列化 /metrics 端点 Prometheus Server HTTP GET /metrics 采集原理关键点 1. Exporter 通过系统 API / 日志 / 协议解析获取原始指标 2. 在 Collect() 中调用 Set() / Observe() 更新 Metric 值 3. Prometheus 按 scrape_interval 定时拉取,默认 15s

2.5 自定义 Exporter 代码示例(Go)

package main

import (
    "net/http"
    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    // Counter:累计请求数
    requestCounter = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total number of HTTP requests",
        },
        []string{"method", "status"},
    )

    // Gauge:当前连接数
    activeConnGauge = prometheus.NewGauge(
        prometheus.GaugeOpts{
            Name: "active_connections",
            Help: "Current number of active connections",
        },
    )

    // Histogram:请求延迟分布
    requestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "HTTP request latency distributions",
            Buckets: prometheus.DefBuckets, // 默认桶:[0.005, 0.01, 0.025, 0.05, ..., 10]
        },
        []string{"method"},
    )
)

func init() {
    prometheus.MustRegister(requestCounter)
    prometheus.MustRegister(activeConnGauge)
    prometheus.MustRegister(requestDuration)
}

func main() {
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}
采集避坑:Exporter 的 Collect() 方法必须快速返回,避免阻塞 Prometheus 抓取。如果采集逻辑涉及远程调用或复杂计算,建议使用 prometheus.NewDesc() 配合异步更新模式,将采集与暴露解耦。

2.6 采集性能与水位口径的关系

在容量压测中,Exporter 的采集性能直接影响水位数据的准确性:

  • 采集延迟:如果 Exporter 采集耗时超过 scrape_timeout(默认 10s),Prometheus 会丢弃该次样本,导致水位数据出现空洞。
  • 样本量控制:每个 Exporter 暴露的 Metric 数量建议控制在 10,000 以内,超过此阈值会显著增加 Prometheus Server 的解析与存储压力。
  • 标签基数:避免高基数标签(如 user_id、request_id),否则会导致 Histogram 的 bucket 数量爆炸,压测水位评估失真。
采集维度推荐值超限影响
单 Exporter Metric 数量< 10,000抓取超时、内存 OOM
单 Metric 标签基数< 100存储膨胀、查询缓慢
采集间隔15s ~ 30s过短增加负载,过长丢失细节
Histogram bucket 数10 ~ 15过多增加存储与计算开销
水位口径优化建议:在压测前,先通过 promtool tsdb analyze 分析现有 Exporter 的采集性能与标签基数,识别出高基数 Metric 并提前降维或删除,确保压测期间水位数据的完整性与准确性。