2. Remote Write 架构解析:Agent 模式、WAL 机制与 Shard/Queue 内部结构
要精准调优 Remote Write 队列,必须先理解其底层架构。本章深入剖析三个核心组件:Prometheus Agent 模式(轻量级采集转发)、Write-Ahead-Log (WAL)(数据持久化与故障恢复基石)、以及 Shard 与 Queue(并发发送与流量控制引擎)。
2.1 Prometheus Agent 模式:专为 Remote Write 而生的轻量级角色
Prometheus 2.32.0 版本引入了 Agent 模式,它剥离了传统 Prometheus Server 的本地存储、查询、告警等重型组件,仅保留采集、服务发现、WAL 写入和 Remote Write 发送功能。这使得 Agent 模式成为边缘节点、Kubernetes 节点级采集、以及大规模联邦场景下的理想选择。
| 特性 | Prometheus Server (默认模式) | Prometheus Agent 模式 |
|---|---|---|
| 本地存储 (TSDB) | 完整 TSDB,支持查询与告警 | 仅保留 WAL,无查询能力 |
| 内存开销 | 较高(需维护内存中的 TSDB 块) | 较低(仅缓存 WAL 与发送队列) |
| 磁盘占用 | 较大(存储历史数据块) | 较小(仅 WAL 文件,可配置保留时间) |
| 启动参数 | --storage.tsdb.retention.time |
--agent 标志启用 |
| 适用场景 | 独立监控、本地告警、临时查询 | 集中式后端、边缘采集、大规模联邦 |
--agent.wal-replay-chunk-size 从默认的 32MB 调整为 64MB,以减少 WAL 回放时的 I/O 次数。
2.2 Write-Ahead-Log (WAL):数据可靠性的基石
WAL 是 Remote Write 流程中数据持久化的第一道防线。所有采集到的样本在发送前,都会先写入 WAL 文件。这确保了即使进程崩溃,数据也不会丢失,重启后可以从 WAL 中恢复并继续发送。
WAL 文件位于 data/wal/ 目录下,由一系列固定大小的段文件(默认 128MB)组成。每个段文件包含多个记录,记录类型包括:
- Series 记录: 存储标签集合(LabelSet)与 Series ID 的映射。
- Sample 记录: 存储时间戳与样本值。
- Tombstone 记录: 标记已删除的 Series(用于清理)。
- Exemplar 记录: 存储示例数据(如 Trace ID 关联)。
--storage.tsdb.wal-segment-size 默认 128MB。对于高吞吐场景(每秒 > 50 万样本),建议增大至 256MB 以减少段文件切换频率,降低 I/O 抖动。但注意,增大段文件会延长崩溃恢复时的回放时间。
2.3 Shard 与 Queue:并发发送的引擎与流量控制
Remote Write 的核心发送逻辑由 Shard(分片) 和 Queue(队列) 协同完成。Shard 是并发发送的 goroutine,Queue 是待发送数据的缓冲区。理解它们的内部结构是调优的关键。
2.3.1 核心数据结构
- Queue (队列): 一个环形缓冲区(Ring Buffer),存储待发送的样本批次。每个批次包含多个样本,由
capacity参数控制总容量。 - Shard (分片): 一个独立的 goroutine,负责从 Queue 中取出批次,执行 HTTP/2 请求发送到远端。Shard 数量由
min_shards和max_shards动态调整。 - Batch (批次): 发送的最小单位,由
max_samples_per_send控制(默认 500 样本/批次)。
2.3.2 动态 Shard 调整机制
Prometheus 会根据发送延迟和队列积压情况,自动在 min_shards 和 max_shards 之间调整 Shard 数量。调整算法基于以下指标:
| 指标名称 | PromQL 查询 | 调优阈值参考 |
|---|---|---|
| 队列剩余样本数 | prometheus_remote_storage_queue_highest_sent_timestamp_seconds - prometheus_remote_storage_queue_samples_in |
持续 > 10000 时触发扩容 |
| 发送延迟 | rate(prometheus_remote_storage_samples_total[5m]) / rate(prometheus_remote_storage_succeeded_samples_total[5m]) |
延迟 > 10s 时触发扩容 |
| Shard 繁忙度 | prometheus_remote_storage_shards_busy |
持续 > 80% 时触发扩容 |
2.3.3 重试与背压机制
当远端返回错误(如 429 Too Many Requests、503 Service Unavailable)时,Shard 会将失败的批次放入 重试队列,采用指数退避策略重试(初始 1s,最大 60s)。重试队列的容量由 retry_on_http_429 和 min_backoff/max_backoff 控制。
- 背压触发条件: 当重试队列积压超过
capacity的 50% 时,WAL 读取器会暂停读取,形成背压,防止内存溢出。 - 数据丢失风险: 如果背压持续超过 5 分钟,WAL 段文件可能被删除(受
wal_cleanup_age控制),导致数据丢失。这是调优中需要极力避免的状态。
max_shards 设置得过大(如 > 1000),否则会导致过多的 HTTP/2 连接和 goroutine 开销,反而降低吞吐。建议从 min_shards=10、max_shards=200 开始,根据实际指标逐步调整。
2.4 架构总结:数据流全景
将上述组件串联起来,Remote Write 的完整数据流如下:
- 采集: Scraper 从目标拉取指标,写入 WAL。
- 持久化: WAL 将数据 fsync 到磁盘,确保崩溃恢复。
- 读取: WAL 读取器从最新段文件读取样本,送入主队列。
- 分片: 分发器根据 Shard 负载,将批次分配给空闲 Shard。
- 发送: Shard 通过 HTTP/2 发送批次到远端,失败则进入重试队列。
- 确认: 远端返回 2xx 后,Shard 从队列中移除该批次,并更新 WAL 的 checkpoint。