适用场景
本文适用于 Prometheus 运行一段时间后出现以下现象的场景:
- Prometheus 数据目录持续膨胀,磁盘空间很快被打满;
prometheus_tsdb_head_series、prometheus_tsdb_head_chunks持续上涨;- 查询变慢,Prometheus 重启时间明显变长;
- 日志中出现 compaction、WAL replay、磁盘空间不足相关报错;
- 明明保留时间设置不长,但实际磁盘占用仍然超出预期。
这类问题通常不是“Prometheus 天生吃磁盘”这么简单,更多时候和采集目标数量、指标标签基数、抓取间隔、保留策略、远程写入失败、业务指标设计有关。
现象描述
巡检时发现 Prometheus 所在节点磁盘告警:
df -h
示例输出:
Filesystem Size Used Avail Use% Mounted on
/dev/vdb1 200G 182G 18G 92% /data
查看 Prometheus 数据目录:
du -sh /data/prometheus
du -h --max-depth=1 /data/prometheus | sort -h
可能看到:
1.8G /data/prometheus/wal
176G /data/prometheus
同时 Prometheus 日志里可能出现:
WAL segment loaded
write block resulted in empty block
compaction failed
no space left on device
如果此时只扩容磁盘,不分析增长来源,通常几天后还会再次打满。
可能原因
Prometheus TSDB 磁盘增长过快,常见原因包括:
- 抓取目标突然增加,例如 Kubernetes Pod 数量扩大;
- 抓取间隔过短,例如大量指标使用
scrape_interval: 5s; - 高基数标签过多,例如把
user_id、request_id、trace_id、完整 URL 放进 label; - 业务指标没有清理,历史版本指标长期保留;
retention.time或retention.size未配置,默认保留时间不符合磁盘容量;- 某个 exporter 暴露了大量动态指标;
- recording rule 生成了过多派生指标;
- remote_write 堵塞导致 WAL 积压;
- Prometheus 重启频繁,WAL replay 时间变长,进一步放大可用性问题。
排查思路
1. 先确认 Prometheus 启动参数
查看 Prometheus 进程参数:
ps -ef | grep prometheus | grep -v grep
重点关注:
--storage.tsdb.path=/data/prometheus
--storage.tsdb.retention.time=15d
--storage.tsdb.retention.size=150GB
--web.enable-lifecycle
关键字段说明:
storage.tsdb.path:TSDB 数据目录;retention.time:按时间保留数据;retention.size:按磁盘体积限制保留数据;- 同时配置时,Prometheus 会尽量满足更先触发的限制;
- 如果没有配置
retention.size,磁盘容量不足时 Prometheus 不会自动按你的磁盘大小停止增长。
如果 Prometheus 由 systemd 管理:
systemctl cat prometheus
systemctl status prometheus
如果运行在 Kubernetes 中:
kubectl get pod -n monitoring -l app=prometheus -o wide
kubectl describe pod -n monitoring <prometheus-pod>
kubectl get cm -n monitoring | grep prometheus
2. 查看 TSDB 核心指标
在 Prometheus 查询页面或 API 中查看:
prometheus_tsdb_head_series
prometheus_tsdb_head_chunks
prometheus_tsdb_storage_blocks_bytes
prometheus_tsdb_wal_storage_size_bytes
rate(prometheus_tsdb_head_samples_appended_total[5m])
判断方式:
head_series持续上涨:活跃时间序列变多,多半是目标增加或标签基数失控;wal_storage_size_bytes持续上涨:WAL 积压,可能是写入压力、远程写入堵塞或 compaction 异常;samples_appended_total速率升高:单位时间写入样本变多,需要检查抓取间隔和指标数量;- blocks 总大小快速增加:长期存储压力已经形成。
3. 找出高基数指标
Prometheus 自带工具 promtool 可以分析 TSDB。
先进入数据目录所在机器:
promtool tsdb analyze /data/prometheus
常见输出会包含:
Highest cardinality metric names:
100203 http_request_duration_seconds_bucket
85120 app_request_total
40211 container_cpu_usage_seconds_total
Highest cardinality labels:
120000 path
85000 pod
60000 instance
如果某个业务指标因为 path、url、user_id 产生大量组合,就会让时间序列爆炸。Prometheus 的成本主要取决于“指标名 + label 组合”的数量,而不是单纯取决于指标名数量。
没有 promtool 时,可以先用 PromQL 粗略判断:
topk(20, count by (__name__)({__name__=~".+"}))
查看某个指标按标签组合后的数量:
count by (job) (http_request_duration_seconds_bucket)
count by (path) (http_request_duration_seconds_bucket)
count by (pod) (container_cpu_usage_seconds_total)
4. 检查 scrape 配置
查看 Prometheus 配置:
grep -n "scrape_interval\\|job_name\\|metrics_path\\|kubernetes_sd_configs" /etc/prometheus/prometheus.yml
重点检查:
global:
scrape_interval: 15s
scrape_configs:
- job_name: "kubernetes-pods"
scrape_interval: 5s
如果大量 job 使用 5 秒抓取,而指标数量又很多,磁盘增长会非常快。一般业务指标可以从 15 秒、30 秒甚至 60 秒开始,根据告警粒度和容量预算再调整。
5. 检查 remote_write 是否堵塞
如果 Prometheus 配置了远程写入,需要关注:
prometheus_remote_storage_samples_pending
rate(prometheus_remote_storage_failed_samples_total[5m])
rate(prometheus_remote_storage_retried_samples_total[5m])
prometheus_remote_storage_shards
判断方式:
samples_pending长时间不下降:远端写入能力不足或网络异常;- failed/retried 持续增长:远端存储、鉴权、限流或网络有问题;
- WAL 目录增长明显:远程写入堵塞可能拖累本地磁盘。
定位示例
某集群 Prometheus 数据目录 3 天内从 60G 增长到 180G。启动参数如下:
--storage.tsdb.path=/data/prometheus
--storage.tsdb.retention.time=30d
没有配置 retention.size。查看写入速率:
rate(prometheus_tsdb_head_samples_appended_total[5m])
发现从 20 万 samples/s 上升到 75 万 samples/s。继续分析:
promtool tsdb analyze /data/prometheus
发现最高基数指标是:
app_http_request_duration_seconds_bucket
标签中 path 数量异常,包含大量真实请求路径:
/api/order/100001/detail
/api/order/100002/detail
/api/order/100003/detail
根因是新版本把订单 ID 放进了 path 标签,没有做路由模板归一化,导致每个订单都生成新的时间序列。
修复方案
1. 立即止血:限制保留体积
先根据磁盘容量设置 retention.size,避免 Prometheus 无限制吃满磁盘。
示例 systemd 启动参数:
--storage.tsdb.retention.time=15d
--storage.tsdb.retention.size=120GB
如果数据盘 200G,不建议把 retention.size 设置到 190G。需要给 WAL、compaction、系统日志和临时文件留空间,一般可以先控制在 60% 到 75%。
修改后重启:
systemctl daemon-reload
systemctl restart prometheus
systemctl status prometheus
Kubernetes 环境则修改对应的 Deployment、StatefulSet、Prometheus CR 或 Helm values,然后滚动更新。
2. 降低抓取频率
对非核心业务指标,将 5 秒抓取调整为 15 秒或 30 秒:
scrape_configs:
- job_name: "app-api"
scrape_interval: 30s
static_configs:
- targets:
- "api:9100"
粗略估算:
日样本量 = 活跃时间序列数量 * 86400 / scrape_interval
如果 100 万条活跃序列从 15 秒改到 30 秒,日写入样本量会直接减半。
3. 修复高基数标签
错误示例:
http_request_duration_seconds{path="/api/order/100001/detail",method="GET"}
http_request_duration_seconds{path="/api/order/100002/detail",method="GET"}
推荐改成路由模板:
http_request_duration_seconds{route="/api/order/{id}/detail",method="GET"}
不要把这些字段放入 label:
- 用户 ID;
- 订单 ID;
- 请求 ID;
- trace ID;
- 完整 URL;
- 错误堆栈;
- 原始 SQL;
- 时间戳。
如果确实需要分析这些维度,应放到日志或 tracing 系统里,而不是 Prometheus label。
4. 使用 relabel 丢弃无用指标
对不需要的指标,可以在抓取侧丢弃:
scrape_configs:
- job_name: "app-api"
metric_relabel_configs:
- source_labels: [__name__]
regex: "go_memstats_.*"
action: drop
也可以丢弃高风险标签:
metric_relabel_configs:
- regex: "request_id|trace_id|user_id"
action: labeldrop
注意:metric_relabel_configs 发生在采集后、写入 TSDB 前,可以减少本地存储压力;但目标端已经生成和传输了这些指标,应用侧仍应从源头治理。
5. 清理过大的历史数据
如果磁盘已经接近打满,优先保住 Prometheus 可启动和可压缩空间。常规方式是调整保留策略后重启,让 Prometheus 自己清理旧 block。
不建议手工删除 WAL 文件。WAL 保存 head block 中尚未落盘的数据,误删可能导致近期数据丢失或启动异常。
如果必须应急删除历史 block,要只删除完整 block 目录,并保留当前 WAL:
ls -lh /data/prometheus
典型 block 目录名称类似:
01J1ABCDEF2G345H6789KLMNPQ
应急删除前至少先停止 Prometheus,并确认目录不是 wal、chunks_head、lock:
systemctl stop prometheus
du -sh /data/prometheus/*
生产环境更推荐扩容磁盘、调小 retention,再让 Prometheus 正常启动后自行清理。
预防措施
- 为 Prometheus 同时配置
retention.time和retention.size; - 对每个 job 设定合理的
scrape_interval,不要全局使用过短间隔; - 建立指标 label 规范,禁止动态 ID 进入 label;
- 新服务接入监控前先检查指标数量和标签维度;
- 对
head_series、WAL 大小、磁盘可用率、样本写入速率设置告警; - 定期用
promtool tsdb analyze审查高基数指标; - 对 Kubernetes Pod 级指标控制采集范围,避免采集无意义的临时任务;
- remote_write 场景要监控 pending、failed、retried 指标。
推荐告警规则示例:
groups:
- name: prometheus-tsdb
rules:
- alert: PrometheusTSDBHighHeadSeries
expr: prometheus_tsdb_head_series > 1000000
for: 10m
labels:
severity: warning
annotations:
summary: "Prometheus active series is too high"
- alert: PrometheusDataDiskAlmostFull
expr: node_filesystem_avail_bytes{mountpoint="/data"} / node_filesystem_size_bytes{mountpoint="/data"} < 0.15
for: 5m
labels:
severity: critical
annotations:
summary: "Prometheus data disk free space is below 15%"
- alert: PrometheusRemoteWriteBacklog
expr: prometheus_remote_storage_samples_pending > 100000
for: 10m
labels:
severity: warning
annotations:
summary: "Prometheus remote write backlog is increasing"
总结
Prometheus 磁盘增长过快时,排查顺序应是:先确认保留策略和数据目录,再看 TSDB 活跃序列、写入速率、WAL 大小,最后定位高基数指标和异常抓取配置。短期可以通过 retention.size、降低抓取频率、清理旧 block 止血;长期要治理指标标签设计、接入规范和容量告警。Prometheus 的稳定性不只靠扩容,关键是控制时间序列规模和样本写入速度。
Discussion
评论