3、指标采集原理:Pull模型 vs Push模型,Exporter设计模式,指标格式规范(OpenMetrics)

好,咱们今天聊一个非常核心的话题——指标到底是怎么从你的服务里「掏」出来的。

我见过不少团队,监控系统搭得挺漂亮,Grafana 面板画得跟艺术品似的,但一问到指标怎么采集的,大家就含糊了。嗯,这块其实特别重要。你想想看,数据源都搞不清楚,后面的告警、分析全是空中楼阁。

这一章,我就把指标采集的三种核心要素掰开揉碎讲清楚:Pull 与 Push 模型Exporter 设计模式,以及OpenMetrics 格式规范

3.1 Pull 模型 vs Push 模型:两种哲学

先说第一个选择题:你的监控系统,是主动去拉数据,还是等数据自己送上门?

这俩思路,说白了就是「拉」和「推」的区别。

3.1.1 Pull 模型:服务端主动出击

Pull 模型是 Prometheus 的招牌动作。监控系统(比如 Prometheus Server)定期去访问你的应用暴露的 HTTP 端点,把指标数据「拉」回来。

优点很明显:

  • 更容易控制采集频率:你可以在监控端统一配置拉取间隔,比如 15 秒一次。想调快调慢,改一处就行。
  • 天然的服务健康检查:如果某个目标拉取失败,说明它可能挂了或者网络不通。这个信息本身就是告警信号。
  • 避免数据洪峰:Push 模式下,如果所有服务同时推送,监控系统可能被冲垮。Pull 模式下,监控端自己掌握节奏。

缺点也实在:

  • 需要服务发现:你得知道哪些目标在运行、在哪个端口。Kubernetes 里还好说,传统环境就得靠 Consul 或文件发现。
  • 网络可达性要求高:监控端必须能连上每个目标。跨机房、跨 VPC 的场景下,这个限制挺头疼的。
我的经验: 在 Kubernetes 集群内,Pull 模型简直是天作之合。Pod 重启、扩缩容,Prometheus 自动感知。但在混合云场景下,我曾经不得不架设一个「代理层」来做 Pull 转发,否则网络不通。

3.1.2 Push 模型:应用主动上报

Push 模型正好反过来。你的应用主动把指标数据发到中央收集器(比如 Graphite、InfluxDB 或 Prometheus Pushgateway)。

优点:

  • 适合短任务:批处理脚本、定时任务,跑完就结束。Pull 模型根本来不及拉,Push 模型可以在任务结束时把指标发出去。
  • 网络拓扑简单:应用只需要能连上收集器,不需要收集器反过来连应用。防火墙规则好配很多。

缺点:

  • 容易产生数据孤岛:如果应用挂了,它就不会 Push 了。你很难区分「没有数据」和「数据为零」。
  • 推送压力不可控:我曾经遇到过一个场景,上千个 Agent 同时推送,直接把收集器的网卡打满了。嗯,那场面挺壮观的。
避坑指南: 我曾经在 Pushgateway 上吃过亏。用它来收集批处理任务指标没问题,但千万别用它来采集长期运行服务的指标。因为 Pushgateway 不会自动清理过期数据,你可能会看到一个月前的 Pod 指标还在那里挂着。

3.1.3 怎么选?

我个人习惯:长期运行的服务,用 Pull;短生命周期任务,用 Push。

如果你用 Prometheus,默认就是 Pull。遇到批处理场景,配合 Pushgateway 做补充。别搞反了。

3.2 Exporter 设计模式:把数据「翻译」成指标

好,模型选完了。下一个问题:你的应用怎么暴露指标?

你总不能在每个业务代码里都写一堆监控逻辑吧?那太耦合了。这时候就需要 Exporter 出场。

Exporter 本质上是一个适配器。它负责从目标系统(比如 MySQL、Redis、Linux 内核)里采集原始数据,然后转换成 Prometheus 能理解的指标格式,通过 HTTP 端点暴露出来。

Exporter 的核心职责就两件事:

  1. 采集:调用目标系统的 API、读取文件、执行命令,拿到原始数据。
  2. 转换:把原始数据映射成 Prometheus 的指标类型(Counter、Gauge、Histogram、Summary)。

我举个例子,你写一个自定义 Exporter 监控某个中间件的连接数:

package main

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

var (
    // 定义一个 Gauge 指标,用于记录当前连接数
    connections = prometheus.NewGauge(prometheus.GaugeOpts{
        Name: "myapp_connections_total",
        Help: "Current number of active connections",
    })
)

func collectMetrics() {
    // 模拟从中间件 API 获取连接数
    connCount := getConnCountFromMiddleware()
    connections.Set(float64(connCount))
}

func main() {
    prometheus.MustRegister(connections)

    // 启动一个 goroutine 定期采集
    go func() {
        for {
            collectMetrics()
            time.Sleep(15 * time.Second)
        }
    }()

    // 暴露 /metrics 端点
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}

你看,这个 Exporter 只做一件事:每 15 秒去中间件拿一次连接数,然后更新到 Prometheus 的 Gauge 指标里。业务代码完全不用改。

核心思想: Exporter 模式实现了「监控逻辑」与「业务逻辑」的解耦。你的团队可以各自维护自己的 Exporter,互不影响。

3.3 指标格式规范:OpenMetrics

最后,数据采集回来了,用什么格式传输?

早期大家各玩各的,Prometheus 自己搞了一套文本格式。后来社区觉得这样不行,得统一标准。于是 OpenMetrics 诞生了。

OpenMetrics 是 CNCF 的孵化项目,它定义了指标数据的标准格式。说白了,就是大家商量好:指标长什么样、怎么描述、怎么换行。

一个标准的 OpenMetrics 指标长这样:

# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",code="200"} 1027 1598970495000
http_requests_total{method="POST",code="500"} 3 1598970495000

我来拆解一下:

  • # HELP:指标的说明文字。告诉运维人员这个指标是干嘛的。
  • # TYPE:指标类型。counter、gauge、histogram、summary 四种之一。
  • 指标行:指标名 + 标签(label)+ 值 + 可选的时间戳。

几个关键规范:

规范项 说明
指标名 只能包含字母、数字、下划线、冒号。不能以数字开头。
标签 键值对,用花括号包裹。标签名只能包含字母、数字、下划线。
时间戳 可选,Unix 毫秒时间戳。如果不带,由接收端自己打时间戳。
编码 必须用 UTF-8,换行符用 \n。
我的习惯: 写 Exporter 时,尽量遵循 OpenMetrics 规范。这样你的指标可以被任何兼容的监控系统消费,不只是 Prometheus。比如 VictoriaMetrics、Thanos 都支持。

3.4 知识体系总览

为了让你更直观地理解这三者的关系,我画了一张图:

指标采集原理知识体系 采集模型 • Pull 模型 服务端主动拉取 • Push 模型 应用主动上报 选型建议: 长服务用 Pull 短任务用 Push Exporter 设计模式 • 适配器模式 采集 + 转换 • 核心职责 调用目标系统 API 映射为 Prometheus 指标 关键点: 解耦业务与监控 指标格式规范 • OpenMetrics CNCF 孵化项目 • 标准格式 HELP / TYPE / 指标行 好处: 跨系统兼容 Prometheus / VictoriaMetrics 三者共同构成完整的指标采集链路

这张图把三个核心概念串起来了。你从左往右看:先决定用 Pull 还是 Push,然后通过 Exporter 把数据翻译成标准格式,最后用 OpenMetrics 规范传输。一条链路,清清楚楚。

一句话总结: Pull 模型适合长服务,Push 模型适合短任务;Exporter 是数据翻译官;OpenMetrics 是通用语言。这三样东西,是构建高并发监控系统的基石。

好了,这一章的内容就到这里。下一章我们会深入指标类型和聚合计算,到时候再聊。


公众号:蓝海资料掘金营,微信deep3321