根本原因是单次抓取指标数据量过大触发OOM Killer,须从数据源头压缩、传输链路控制和内存策略三方面协同解决:限制样本数、精简高风险指标、启用sample_limit、引入代理裁剪、客户端聚合及调整TSDB块时长。

直接原因是单次抓取返回的指标数据量过大,超出Prometheus内存处理能力,触发内核级OOM Killer强制终止进程。这不是配置调优能绕开的问题,必须从数据源头压缩、传输链路控制和内存使用策略三方面协同解决。
限制单次抓取的数据规模
核心是让每个target在一次scrape中返回的样本数可控。重点检查以下几类高风险指标:
-
未加label过滤的直方图/摘要指标:如
http_request_duration_seconds_bucket带大量le分位点 + 多维label,极易爆炸式膨胀;建议只保留关键分位(如le="0.1", "0.2", "0.5", "1"),其余drop掉 -
含高基数label的计数器:比如
request_total{path="/api/v1/users/<uuid>", method="GET"}</uuid>,其中<uuid>是动态值,每条请求生成新时间序列;必须通过relabel_configs用正则替换或hash掉该label - 全量暴露的runtime/metrics(如Go pprof):默认包含goroutine、heap等高频高维指标;应关闭非必要端点,或仅在调试时临时启用
调整抓取行为与缓冲机制
避免内存瞬时峰值压垮进程:
- 将
scrape_timeout设为略高于实际响应时间(如15s),但不要盲目拉长;超时过长会堆积未完成抓取,反而加剧内存压力 - 启用
sample_limit(v2.15+):在job级别硬性限制单次抓取最多接收的样本数,超出部分直接丢弃并打日志,防止失控;例如设为sample_limit: 100000 - 对已知“重目标”单独配置
metric_relabel_configs,优先删除低价值指标(如go_gc_duration_seconds这类辅助指标)
规避物理熔断的兜底策略
当OOM已频繁发生,需快速止血并建立防护层:
- 在Prometheus前加一层轻量代理(如Claw-Prometheus),由它完成目标发现、协议转换、指标裁剪和缓存,再以稳定节奏向Prometheus提供精简后的metrics;这样即使后端目标抖动,也不会传导到Prometheus内存
- 对pushgateway类场景,禁止业务方直接推送原始细粒度指标;改为在客户端聚合(如按分钟汇总QPS、P95延迟),再推送聚合后指标
- 设置
--storage.tsdb.max-block-duration=2h和--storage.tsdb.min-block-duration=2h,强制WAL压缩更激进,减少内存中待刷盘样本堆积
物理熔断本质是系统保护机制,不是故障而是预警。真正要做的,是让每次scrape变成可预期、可计量、可截断的操作,而不是依赖Prometheus硬扛。

















