适用场景
本文适用于 Prometheus 通过 remote_write 把指标发送到 Thanos Receive、Grafana Mimir、VictoriaMetrics 或其他远端存储的场景。典型问题是本地抓取仍然正常,Prometheus 查询近期数据也没有明显异常,但远端查询、告警或长期存储中的数据逐渐落后,最终出现缺口。
这类故障的关键不是盲目增大队列,而是先区分下游变慢、网络重试、样本突增和本地资源不足,再决定扩容、限流还是调整队列参数。
现象描述
常见现象包括:
- 远端存储中的最新时间戳落后当前时间数分钟甚至数小时;
- Prometheus 本地规则计算正常,但依赖远端数据源的仪表盘出现延迟;
prometheus_remote_storage_samples_pending持续增长;prometheus_remote_storage_samples_retried_total或prometheus_remote_storage_samples_failed_total快速增加;prometheus_remote_storage_shards已接近配置上限,吞吐仍追不上写入速度;- Prometheus 内存、CPU 或磁盘 I/O 同时升高,重启后短暂恢复,随后再次积压。
先从 Prometheus 自身指标确认延迟,而不是只看下游页面:
time()
- prometheus_remote_storage_queue_highest_sent_timestamp_seconds
结果表示最后成功发送样本相对当前时间的滞后秒数。多条 remote_write 配置时,应按 url、remote_name 等当前版本实际暴露的标签拆分观察。
再看待发送样本是否持续累积:
prometheus_remote_storage_samples_pending
如果发送延迟和 Pending 同时上升,可以确认队列正在积压;如果只有远端查询变慢而发送时间戳正常,应把重点转向远端存储的查询链路,而不是 Prometheus 写队列。
可能原因
- 远端存储限流、过载或返回
429、5xx,导致 Prometheus 退避重试。 - DNS、TLS、代理或负载均衡链路不稳定,请求频繁超时或重置。
- 新增高基数标签后,每秒样本数突然增加,超过原有队列吞吐。
- 单个请求过大或下游响应过慢,批量发送耗时显著上升。
max_shards太小,队列无法增加足够并发;也可能设置过大,反而压垮下游。- Prometheus CPU、内存或磁盘 I/O 饱和,WAL 读取和样本编码无法及时完成。
- 下游恢复后瞬间释放大量积压,形成恢复流量尖峰,再次触发限流。
排查思路
1. 建立故障时间线
同时绘制抓取速率、Pending、重试、失败和分片数,避免只依据单个瞬时值判断。
sum(rate(prometheus_remote_storage_samples_in_total[5m])) by (remote_name)
sum(rate(prometheus_remote_storage_samples_retried_total[5m])) by (remote_name)
sum(rate(prometheus_remote_storage_samples_failed_total[5m])) by (remote_name)
prometheus_remote_storage_shards
指标标签和部分名称可能随 Prometheus 版本变化,上线告警前应先在 /graph 或 /api/v1/label/__name__/values 中确认本机实际暴露值。判断逻辑如下:
- 输入速率突增、重试很少:优先检查样本量和队列吞吐;
- 重试速率上升:优先检查下游状态码、超时和网络;
- 失败速率上升:检查不可重试错误、认证、样本格式和下游拒绝原因;
- 分片数顶到
max_shards:现有并发上限可能不足,但必须先确认下游还有余量。
2. 检查 Prometheus 日志
journalctl -u prometheus \
--since "30 min ago" \
| grep -E 'remote write|non-recoverable|429|timeout|connection reset'
容器化部署可使用:
kubectl -n monitoring logs prometheus-k8s-0 \
--since=30m \
| grep -E 'remote write|non-recoverable|429|timeout|connection reset'
重点区分:
429:下游明确限流,继续提高并发通常会加重问题;5xx或超时:下游容量或链路异常,样本通常会重试;4xx且标记为不可恢复:常见于认证、租户头、标签或时间戳不合法,重试无法解决;- TLS 或 DNS 错误:优先修复连接链路,不要用扩大队列掩盖。
日志可能包含远端地址和租户信息,采集与共享时应脱敏,不要输出认证头或令牌。
3. 确认样本量是否突增
sum(rate(prometheus_tsdb_head_samples_appended_total[5m]))
如果该值在故障前明显抬升,可继续按任务拆分抓取样本量:
topk(10, sum by (job) (rate(scrape_samples_post_metric_relabeling[5m])))
对比 scrape_samples_scraped 与 scrape_samples_post_metric_relabeling,可以确认 relabel 后实际进入 Prometheus 的样本规模。常见诱因是把 user_id、request_id、完整 URL 或容器实例随机值写入标签。
4. 检查本机资源与 WAL
rate(process_cpu_seconds_total{job="prometheus"}[5m])
process_resident_memory_bytes{job="prometheus"}
df -h /var/lib/prometheus
df -i /var/lib/prometheus
iostat -xz 1 10
磁盘高延迟、空间不足或内存频繁触顶都会影响 WAL 和远端写队列。不要在积压期间直接删除 WAL;这会把可恢复的待发送样本变成永久数据缺口。
配置调整示例
下面配置展示一个受控起点,具体值应依据实际样本速率、下游写入容量和 Prometheus 内存预算压测确定:
remote_write:
- url: https://metrics.example.com/api/v1/write
remote_timeout: 30s
queue_config:
capacity: 10000
min_shards: 2
max_shards: 20
max_samples_per_send: 2000
batch_send_deadline: 5s
min_backoff: 100ms
max_backoff: 5s
关键参数含义:
capacity:每个分片的缓冲容量。增大会提高短时抗抖动能力,也会增加内存占用;min_shards:最低发送并发,流量较小时不必维持大量连接;max_shards:自动扩展的并发上限,必须与下游限流和连接容量匹配;max_samples_per_send:单批样本数,过小会增加请求开销,过大则会拉长单次失败后的重试时间;batch_send_deadline:低流量下等待凑批的最长时间;min_backoff、max_backoff:可重试错误的退避范围,防止故障期间持续冲击下游。
修改后先校验配置:
promtool check config /etc/prometheus/prometheus.yml
如果使用 Kubernetes Operator,应修改对应的 Prometheus 自定义资源或受管配置,不要直接编辑生成后的 Pod 内文件。
安全恢复步骤
- 先确认下游已恢复且有足够余量,避免在故障状态下继续加压。
- 保持 Prometheus 运行,让它从 WAL 中逐步追赶;不要用重启代替诊断。
- 如果分片长期顶到上限且下游资源充足,小步提高
max_shards,每次调整后观察发送延迟、429、CPU 和内存。 - 若样本量突增来自错误标签,先通过
metric_relabel_configs丢弃无价值高基数标签或指标。 - 恢复期间设置并发和速率边界,避免积压回放压垮刚恢复的下游。
- 当 Pending 下降且最高已发送时间戳持续追近当前时间,再宣布恢复完成。
例如删除不应进入时序标签的请求标识:
scrape_configs:
- job_name: application
static_configs:
- targets: ["app:9100"]
metric_relabel_configs:
- action: labeldrop
regex: "request_id|trace_id|user_id"
labeldrop 会改变时序身份,实施前必须确认这些标签不是告警、聚合或排障所必需。更理想的做法是在埋点源头不要生成无界标签。
告警与预防
发送延迟告警可以从 5 分钟阈值起步,并要求持续一段时间,避免短时网络抖动造成噪声:
groups:
- name: prometheus-remote-write
rules:
- alert: PrometheusRemoteWriteLagging
expr: |
time() - prometheus_remote_storage_queue_highest_sent_timestamp_seconds > 300
for: 10m
labels:
severity: warning
annotations:
summary: "Prometheus remote_write 发送延迟超过 5 分钟"
description: "远端写入队列持续落后,请检查 Pending、重试率、下游状态与样本增量。"
还应建立以下保护:
- 对 Pending、发送延迟、重试率、失败率和分片利用率建立组合告警;
- 对每个
job的样本数和序列数设置基线,及时发现基数突增; - 为远端存储设置明确的写入 SLO、限流容量和故障演练;
- 配置 Prometheus 磁盘空间与 WAL 保留窗口告警;
- 变更 exporter、采集标签或 remote_write 参数时先做小范围验证;
- 把配置校验纳入发布流水线,并保留可快速回滚的上一版本配置。
总结
Prometheus remote_write 延迟上升,本质上是样本进入速度长期高于成功发送速度。排查时应先用最高已发送时间戳确认真实延迟,再结合 Pending、重试、失败、分片数和样本输入速率定位瓶颈。下游限流时盲目提高并发会让故障恶化;样本基数失控时单纯扩容队列也只能延后爆发。通过受控分片、合理批量、退避重试、高基数治理和组合告警,才能让积压可观测、恢复有边界,并避免把短时抖动演变为长期数据缺口。
Discussion
评论