2. 存储瓶颈根因分类:TSDB写入放大、WAL积压、Block合并延迟、内存Chunk溢出、磁盘IOPS打满等常见根因的归类与特征
Prometheus TSDB 的存储瓶颈并非单一故障,而是多种根因交织的结果。SRE 在复盘时,需要快速将现象归类到对应的根因类别,才能制定有效的恢复策略。本节将五大常见根因进行结构化分类,并给出每个类别的核心特征与判别指标。
2.1 根因分类全景图
以下 SVG 展示了五大根因的层级关系与数据流影响路径,帮助你在复盘时快速定位问题域。
2.2 根因归类与特征矩阵
下表从触发条件、核心指标、典型现象、恢复手段四个维度,对五大根因进行横向对比。
| 根因类别 | 触发条件 | 核心指标 | 典型现象 | 恢复手段 |
|---|---|---|---|---|
| 写入放大 | 高基数 label 组合、频繁的 label 变更 | prometheus_tsdb_head_series prometheus_tsdb_compactions_total |
CPU 持续 80%+,磁盘写入量 > 采集量 5x | 降低基数、启用 label 降维、调整压缩策略 |
| WAL 积压 | 写入峰值超过 WAL 回放速度、磁盘 IO 抖动 | prometheus_tsdb_wal_storage_size_bytes prometheus_tsdb_wal_corruptions_total |
WAL 目录大小持续增长,重启后回放时间 > 5min | 限流写入、扩容磁盘、启用 WAL 压缩 |
| Block 合并延迟 | 内存不足、压缩队列积压、Block 数量 > 100 | prometheus_tsdb_compactions_skipped_total prometheus_tsdb_blocks_loaded |
查询延迟增加,Block 目录碎片化严重 | 增加内存、调整 --storage.tsdb.retention.size |
| 内存 Chunk 溢出 | 瞬时高基数写入、head chunk 未及时落盘 | prometheus_tsdb_head_chunks process_resident_memory_bytes |
OOM 重启、远端写失败、查询返回 503 | 限制 series 数量、启用 chunk 预分配 |
| 磁盘 IOPS 打满 | 大量 Block 合并、WAL 回放、查询扫描 | node_disk_io_time_seconds_total node_disk_reads_completed_total |
iowait > 30%,所有读写操作排队 | 更换 SSD、分离数据与 WAL 磁盘、限流 |
复盘提示: 在 MTTR 复盘时,优先检查
prometheus_tsdb_head_series 和 prometheus_tsdb_wal_storage_size_bytes 两个指标。如果 series 数量超过 1000 万且 WAL 大小超过 10GB,基本可以判定为写入放大 + WAL 积压的组合根因。
2.3 根因特征详解
2.3.1 写入放大
写入放大是 Prometheus TSDB 最隐蔽的瓶颈。当 label 组合基数过高时,每个新 series 都会触发一次完整的 index 写入和压缩操作,导致实际磁盘写入量远大于采集数据量。
- 特征指标:
rate(prometheus_tsdb_compactions_total[5m])持续 > 10,且rate(prometheus_tsdb_head_series_created_total[5m])与rate(prometheus_tsdb_head_samples_appended_total[5m])比值 > 1:100。 - 典型场景: 容器 label 中包含 pod IP、container_id 等高频变化字段。
- 恢复策略: 使用
honor_labels: false或 relabel 丢弃高基数 label。
2.3.2 WAL 积压
WAL 积压通常发生在写入峰值超过磁盘写入能力时。WAL 文件无法及时被回放并转换为 Block,导致目录大小持续膨胀。
- 特征指标:
prometheus_tsdb_wal_storage_size_bytes在 30 分钟内增长超过 2GB,且prometheus_tsdb_wal_replay_duration_seconds在重启时 > 300s。 - 典型场景: 大规模集群同时推送数据,或远端写目标不可用导致本地缓存积压。
- 恢复策略: 临时关闭部分采集任务,或扩容 WAL 所在磁盘的 IOPS。
2.3.3 Block 合并延迟
Block 合并是 TSDB 的后台任务,当内存不足或压缩队列积压时,合并操作被跳过,导致 Block 数量过多,查询性能下降。
- 特征指标:
prometheus_tsdb_compactions_skipped_total非零,且prometheus_tsdb_blocks_loaded> 200。 - 典型场景: 长期运行未重启的 Prometheus 实例,且 retention 设置过大。
- 恢复策略: 调整
--storage.tsdb.retention.size为总磁盘的 60%,或手动触发POST /api/v1/admin/tsdb/clean_tombstones。
2.3.4 内存 Chunk 溢出
内存 Chunk 溢出是瞬时性的致命瓶颈。当 head chunk 无法及时落盘时,内存持续增长直至 OOM。
- 特征指标:
prometheus_tsdb_head_chunks在 1 分钟内增长超过 50%,且process_resident_memory_bytes接近内存上限。 - 典型场景: 突发流量导致 series 数量在 10 秒内翻倍。
- 恢复策略: 立即限流写入,并启用
--storage.tsdb.head-chunks-write-queue-size参数。
2.3.5 磁盘 IOPS 打满
磁盘 IOPS 打满是所有根因的最终表现形式,也可能是独立的硬件故障。当 Block 合并、WAL 回放、查询扫描同时发生时,磁盘成为最薄弱的环节。
- 特征指标:
node_disk_io_time_seconds_total的 rate > 0.8,且node_disk_reads_completed_total和node_disk_writes_completed_total均处于高位。 - 典型场景: 使用 HDD 或低端 SSD 的 Prometheus 实例。
- 恢复策略: 将数据目录迁移到高性能 SSD,或分离 WAL 与数据到不同磁盘。
2.4 根因判别流程
以下 SVG 展示了从现象到根因的判别决策树,帮助 SRE 在 5 分钟内完成初步归类。
常见误区: 不要将“磁盘 IOPS 打满”作为唯一根因。在大多数情况下,IOPS 打满是写入放大、WAL 积压或 Block 合并延迟的结果。如果只扩容磁盘而不解决上层根因,瓶颈会在 24 小时内再次出现。
2.5 根因归类检查清单
在 MTTR 复盘时,使用以下清单快速完成根因归类:
- 检查 CPU 和 iowait: 如果 CPU > 80% 且 iowait < 20%,优先排查写入放大和内存 Chunk 溢出。
- 检查 WAL 目录大小: 如果
wal目录 > 10GB,直接归类为 WAL 积压。 - 检查 Block 数量: 如果
blocks目录下子目录 > 200,归类为 Block 合并延迟。 - 检查 series 变化率: 如果
prometheus_tsdb_head_series在 5 分钟内增长 > 50%,归类为内存 Chunk 溢出。 - 检查磁盘 IO 队列长度: 如果
node_disk_io_now持续 > 10,且以上均不满足,归类为磁盘 IOPS 打满。
复盘最佳实践: 在 Prometheus 的告警规则中,提前为每个根因类别配置独立的告警。例如,当
prometheus_tsdb_wal_storage_size_bytes > 10GB 时触发“WAL 积压”告警,而不是笼统的“存储瓶颈”告警。这可以将 MTTR 缩短 40% 以上。