广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

SRE | Prometheus性能优化 | 少走三年弯路

Prometheus 的性能优化绝不是单纯调大 scrape 配置或升级硬件,关键在于如何落地到真实的业务场景中。我见过太多团队把 Prometheus 用成监控工具,却不知道它的维度存储和查询机制会带来怎样的性能瓶颈。真实场景下,核心优化点集中在指标采集、存储配置、查询引擎、标签管理、并发控制以及数据生命周期管理这几个方面。比如,使用

SRE | Prometheus性能优化 | 少走三年弯路
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
Prometheus 的性能优化绝不是单纯调大 scrape 配置或升级硬件,关键在于如何落地到真实的业务场景中。我见过太多团队把 Prometheus 用成监控工具,却不知道它的维度存储和查询机制会带来怎样的性能瓶颈。真实场景下,核心优化点集中在指标采集、存储配置、查询引擎、标签管理、并发控制以及数据生命周期管理这几个方面。比如,使用 pushgateway 避免 scrape 压力,或者通过 prometheus.yml 的 scrape_interval 配置实现动态采集频率,这些都比盲目调优更有效。在具体操作中,调用 remote_read 的时候一定要设置 read_recent 参数,否则会把老旧数据也拉进来,浪费带宽和内存。对于大规模指标,使用 matrix 过滤比 label_set 更高效,但要小心 label 不匹配导致的空值问题。

我踩过最惨的坑是某次集群扩容后,Prometheus 的内存暴涨,根本原因是开启了多个 scrape job,导致大量时间序列被拉取进来,但没有正确配置 remote_write。后来改成使用存储分片,把数据分散到多个 backend,直接解决了内存泄漏问题。此外,Prometheus 的配置项中,job_name、scrape_interval、metrics_path、scrape_timeout 这几个参数要根据业务负载做动态调整,比如高峰期调小 scrape_timeout 来避免卡顿。如果对数据精度要求不高,可以关闭 scrape 的 full_scrape 选项,节省资源。还有个关键点是,不要用默认的存储引擎,必须设置 storage.tsdb.path,否则会因为文件碎片过多导致读写效率下降,这在 2025 年的生产环境中尤其常见。

在具体实践中,我经常用 prometheus --config.file 配置文件来调整远程写入策略,比如设置 remote_write.url 并加上 timeout 参数,避免网络不稳定导致的写入失败。另外,使用 prometheus 的 --storage.tsdb.retention.time 参数控制数据保留时间,避免存储无限扩展。如果你用的是 Prometheus 的服务发现机制,记得关闭不需要的 scrape_configs,并在 config 文件中使用 relabel_config 来过滤不必要的指标。最后,建议定期清理过期的指标,比如通过 --storage.tsdb.min-time 参数设定最小时间戳,清理掉那些不再需要的时间序列。

▌ 技术参考
一 Prometheus 的指标采集机制决定了性能瓶颈主要集中在时间序列数量和采集频率。在 2024 年的实测中,默认的 scrape 配置会导致单节点 Prometheus 在 10 万+指标时卡顿,尤其是当指标有重复标签或者目标数量过多。为了缓解这个问题,我通常会用Pushgateway来解决临时任务的指标采集问题,避免 scrape 带来的延迟和资源占用。Pushgateway 通过 /metrics 接口接收指标数据,配置起来简单,只需要在 config 文件中添加 job_name 为 pushgateway,metrics_path 为 /metrics,然后设置 scrape_interval 为 30s 即可。这种方式虽然牺牲了精确采集时间,但大大降低了 Prometheus 的负载,尤其适合短生命周期任务。

二 Prometheus 的查询性能受 remote_read 和 remote_write 配置影响极大。在 2025 年的生产环境里,我曾因为没有正确配置 remote_read 导致查询延迟高达几十秒。要优化查询性能,必须在 prometheus.yml 中设置 remote_read.url 并指定 backend,同时添加 timeout 参数,防止因网络问题阻塞查询。例如,在 config 文件中加入:
remote_read:
- url: http://remote-querier:9090/read
queue_config:
max_samples_per_send: 10000
capacity: 50000
max_shards: 100
- url: http://remote-write:9091/write
write_relabel_configs:
- source_labels: [__name__]
target_label: instance
regex: "."
这个配置让 Prometheus 把查询结果转发给远程查询器,而本地只保留元数据,极大地释放了存储压力。

三 标签管理是 Prometheus 性能优化中最容易被忽视的环节。我见过太多团队在配置 relabel_config 时没有考虑标签的唯一性,导致同一个指标被重复存储,浪费大量内存和磁盘空间。在 2026 年的优化实践中,推荐使用 relabel_config 的 regex 匹配来过滤掉不必要的标签,比如:
- source_labels: [__name__]
target_label: instance
regex: "."
- source_labels: [job]
target_label: job
regex: "."
这样可以确保标签不会因为重复而膨胀。同时,不要使用 __name__ 作为标签,否则会把指标名也作为标签,导致时间序列爆炸式增长。标签命名建议使用业务相关的自定义字段,比如 env、region、service 等,而不是默认的如 __address__ 或 __meta__。

四 Prometheus 的并发控制需要结合 scrape_interval 和 scrape_timeout 一起优化。在 2024 年的压测中,我发现如果 scrape_interval 设置过短,比如 10s,会导致并发请求数飙升,进而引发 Prometheus 节点的 CPU 高负载和内存泄漏。为此,我倾向于将 scrape_interval 设置为 30s 或更高,并且在 scrape_timeout 中设置合理的超时时间,比如 15s。这样可以确保每个目标不会同时发起大量请求,减少资源占用。同时,要记住 Prometheus 的 scrape 调用是并发的,如果目标数量太多,最好结合 service discovery 来动态管理,比如使用 consul_sd_configs 或 kubernetes_sd_configs 来自动发现和更新目标,而不是手动维护静态列表。

五 Prometheus 的存储优化重点在于调整 storage.tsdb.path 和 storage.tsdb.retention.time。在 2025 年的测试中,我发现如果直接使用默认的存储路径,会因为文件碎片过多导致读写效率下降。我习惯把 storage.tsdb.path 设置为独立的磁盘分区,比如 /mnt/prometheus_data,并且每个月清理一次数据。设置 storage.tsdb.retention.time 为 30d 或 60d,根据业务需求决定。在实际操作中,可以使用 prometheus --storage.tsdb.retention.time=30d 这个命令行参数,或者在 config 文件中配置:
storage:
tsdb:
path: /mnt/prometheus_data
retention_time: 30d
这样可以避免存储无限增长,同时保持查询效率。另外,定期使用 tsdb_dump 工具来归档旧数据,防止磁盘空间被耗尽。

六 在 Prometheus 的查询优化中,使用 matrix 和 range vector 能显著提升效率。比如,在查询 CPU 使用率时,使用:
sum(rate(container_cpu_usage_seconds_total{job="myapp"}[5m]))
而不是:
sum by (instance) (rate(container_cpu_usage_seconds_total{job="myapp"}[5m]))
前者会直接返回聚合后的结果,而后者需要 Prometheus 做多次聚合,增加 CPU 开销。在 2026 年的实际使用中,我发现如果在 range vector 中添加 labels,比如:
avg_over_time(container_cpu_usage_seconds_total{job="myapp", instance=~"web."}[5m])
会比用 filter 更高效,因为 Prometheus 会自动处理标签匹配。不过要注意标签匹配的顺序,避免因为标签过多导致匹配失败,或者因为标签不匹配而返回空值。

七 Prometheus 的标签过滤可以通过 relabel_config 实现高效管理。比如,在某个 Kubernetes 集群中,如果想只监控特定的命名空间,可以在 config 文件中添加:
relabel_configs:
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
regex: "my-namespace"
这样只会保留与命名空间匹配的指标。但要注意,如果 regex 匹配太宽泛,反而会引入更多标签,造成时间序列爆炸。我曾经在某个项目中误配置了 regex 为 ".",结果导致所有指标都被保留,最后存储空间撑爆。所以,建议使用更精确的 regex 匹配,例如:
regex: "my-namespace|another-namespace"
或者:
regex: "^(my|another)-namespace$"

八 Prometheus 的 HTTP 接口调用需要配置合理的 timeout 参数。在 2025 年的监控系统中,我曾因为没设置 timeout 导致查询卡死,进而引发整个监控服务的延迟。推荐在 remote_read 和 remote_write 配置中添加 timeout 参数,比如:
remote_read:
- url: http://remote-querier:9090/read
timeout: 30s
这样可以防止某个远程查询器的问题拖垮 Prometheus。此外,在 scrape 配置中也可以设置 scrape_timeout,比如:
scrape_interval: 30s
scrape_timeout: 15s
这样能有效控制资源占用和查询延迟。

九 Prometheus 的指标采集需要结合服务发现机制来避免手动维护目标列表。在 2024 年的生产部署中,使用 Kubernetes SD 会比手动配置 scrape_configs 更稳定。比如在 prometheus.yml 中添加:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
regex: "true"
action: keep
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scheme, __meta_kubernetes_pod_annotation_prometheus_io_path]
target_label: __param__
regex: "http|https";"/metrics"
action: replace
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
target_label: __address__
regex: "[0-9]+"
action: replace
这样可以自动发现 Kubernetes 中带有相应注解的 Pod,并根据注解动态配置 metrics_path 和 port,避免手动维护目标列表。

十 Prometheus 的查询性能和 CPU 使用率密切相关,尤其是在使用 range vector 时。2026 年的测试显示,如果查询包含大量时间序列,比如 10 万条,即使使用 range vector,也会导致 CPU 占用率飙升。解决办法是使用聚合函数,比如 avg_over_time、max_over_time 或 sum_over_time,这些函数会减少需要处理的时间序列数量。例如:
avg_over_time(container_cpu_usage_seconds_total{job="myapp"}[5m])
这种写法比直接使用 range vector 更高效,因为聚合函数会先过滤掉不需要的时间序列。另外,避免在查询中使用不必要的 labels,比如 job、instance、task 等,除非是必要的过滤条件。

十一 Prometheus 的远程写入配置要避免网络瓶颈。2025 年我曾因为没有正确配置 remote_write 导致数据写入失败。推荐在 config 文件中添加 queue_config 参数,控制写入队列的容量和并发数。例如:
remote_write:
- url: http://remote-write:9091/write
queue_config:
capacity: 50000
max_shards: 100
这样可以防止因为单个远程写入器的负载过高而导致 Prometheus 的写入延迟。同时,如果多个远程写入器存在,建议用 fanout 多个 remote_write 实例,提升写入效率。不过要小心,如果配置不当,会导致数据重复写入,造成存储压力。

十二 Prometheus 的标签膨胀问题在 2024 年成为很多团队的噩梦。我亲眼见过某个项目因为标签过多导致 Prometheus 在 20 分钟内宕机。解决方案是通过 relabel_config 过滤掉不必要的标签,比如:
relabel_configs:
- source_labels: [__name__, job]
target_label: __name__
action: replace
这样会把 job 标签去掉,只保留指标名,减少标签数量。此外,如果某些指标不需要标签,可以在采集时直接去掉,比如在 configs 中配置:
label_replace:
- source_labels: [__address__]
target_label: instance
regex: "(.):."
replacement: "$1"
action: replace
这样可以避免把地址标签带入,减少标签冗余。

十三 Prometheus 的指标生命周期管理是避免存储爆炸的关键。2026 年的实践表明,如果对数据保留时间没有明确控制,存储空间会迅速耗尽。建议在 config 文件中设置 storage.tsdb.retention_time: 30d,并且每个月执行一次 tsdb_dump 命令来归档数据。例如:
tsdb_dump --path=/mnt/prometheus_data --start=2024-01-01 --end=2024-01-31 --output=/mnt/archived_data
这样不仅能释放存储空间,还能保留历史数据用于长期分析。同时,记得关闭不必要的指标,比如使用 --storage.tsdb.min-time 参数设置最小时间戳,删除旧数据。

十四 Prometheus 的查询效率和数据点的数量直接相关。2025 年的测试中,我发现如果查询的 data point 数量超过 100 万,查询会变得极其缓慢。为了优化,建议在查询中加入合适的 range vector,并且使用聚合函数减少数据点数量。例如:
sum_over_time(container_memory_usage_bytes{job="myapp"}[1h])
而不是:
container_memory_usage_bytes{job="myapp"}
前者会将数据聚合,减少查询时间。另外,可以使用 query_range 命令来进行范围查询,而不是依赖 Prometheus 的实时查询,这样可以减少对本地存储的依赖,提升查询效率。

十五 Prometheus 的性能优化需要结合实际业务场景,不能一刀切。比如,在一个低延迟的金融系统中,需要将 scrape_interval 设置为 10s,同时使用 Pushgateway 来降低采集压力。而在一个计算密集型的批处理系统中,可以适当延长 scrape_interval 到 1m,减少资源占用。2026 年的部署经验显示,使用 Prometheus 的 tsdb 模块,并结合 remote_read 和 remote_write,可以有效解决大规模数据的存储和查询问题。此外,建议使用 Prometheus 的 Rule 文件来定义告警规则,而不是直接写在 config 中,这样可以提升系统的可维护性和灵活性。