prometheus指标经历服务发现、抓取、标签处理、内存写入、刷盘归档五阶段流转,标签贯穿全程并决定数据识别与查询效率。

一个 Prometheus 指标不是“一抓就存”,而是经历明确阶段的结构化流转:从服务发现生成目标,到拉取样本、打标签、写入内存,再到刷盘成块、压缩归档。每个环节都由特定组件驱动,且标签(labels)贯穿始终,决定数据如何被识别、分类和查询。
服务发现与目标生成
Prometheus 启动时,先根据 scrape_configs 中的 job 配置触发服务发现(Service Discovery)。支持多种方式:静态配置(static_configs)、DNS、Kubernetes、Consul 等。无论哪种方式,最终都输出一组 target——即待抓取的 HTTP 地址(如 10.0.1.5:9100/metrics)。
每个 target 自动附带默认标签:__address__(地址)、__scheme__(协议)、__metrics_path__(路径),这些是内部临时标签,后续会被处理或删除。
- 可通过
relabel_configs在目标层面修改或过滤标签,例如将__address__提取为instance,或按环境标签(env=prod)保留/丢弃目标 - 目标列表会定期刷新(默认每 30 秒),确保动态环境(如 K8s Pod 变更)能被及时纳入监控范围
指标抓取与样本处理
Retrieval 模块按配置的 scrape_interval(如 15s)轮询每个 target 的 /metrics 接口,获取文本格式指标(如 http_requests_total{method="GET",status="200"} 1245)。
抓取到的原始样本会经过两层标签处理:
- 第一层:基于 target 标签 + 指标本身标签,构建完整时间序列标识(如
http_requests_total{job="api",instance="10.0.1.5:9100",method="GET",status="200"}) - 第二层:通过
metric_relabel_configs对样本级标签做最后清洗——可 drop 无用指标(如调试用的debug_*)、重命名标签、或添加全局维度(如cluster="east")
注意:任何标签变更(增、删、改)都会产生**新时间序列**;相同指标名+不同标签组合 = 不同序列,存储与查询开销随之增加。
内存写入与持久化落盘
处理后的样本首先进入 TSDB 的 Head Block(内存块),这里支持高吞吐写入,并维护最近 2 小时左右的数据。
为防崩溃丢失,所有写入同时记入 WAL(Write-Ahead Log),即预写日志。WAL 文件按固定大小滚动,重启时可回放恢复 Head 数据。
- 当 Head Block 达到一定时间(默认 2 小时)或大小阈值,它会被“切片”并 compact 成一个只读的 Block(目录形式,含 index、chunks、meta.json)
- Block 写入本地磁盘(
--storage.tsdb.path),并自动参与查询;旧 Block 会按--storage.tsdb.retention.time(如 15d)定期清理 - TSDB 不直接覆盖旧数据,而是通过追加写 + 后台 compact 实现高效更新与去重
标签设计直接影响生命周期效率
标签不是装饰,而是 Prometheus 数据组织的骨架。不当使用会导致序列爆炸、内存飙升、查询变慢。
- 避免高基数标签:如
user_id="abc123"、request_id="xxx"—— 它们会让单个指标分裂成成千上万个序列 - 优先用低基数、稳定、可聚合的维度:如
service="auth"、env="prod"、region="us-east" - 用
labeldrop/labelkeep在采集端过滤,比在查询端sum by()更节省资源 - 指标名应表达语义,标签承载维度;不要把路径、状态码拼进指标名(如
http_get_200_api_v1_users),而要用http_requests_total{method="GET",status="200",path="/api/v1/users"}











