生产环境Prometheus高可用架构实战:从双写到联邦集群的演进之路
前言:单点Prometheus的生产危机
在早期的微服务架构中,单实例Prometheus似乎足以应对监控需求。直到某天凌晨,核心集群的Prometheus节点因磁盘IO瓶颈宕机,我们才发现:监控系统的可用性直接决定了故障恢复的速度。
生产环境的Prometheus高可用并非简单的"多副本部署",而是涉及数据一致性、查询聚合、长期存储的系统性工程。本文基于笔者在电商和金融场景的实战经验,梳理从双写到联邦集群的架构演进路径,帮助你在不同业务阶段做出正确的技术选型。
第一阶段:双写(Double Write)—— 快速止损的权宜之计
架构原理
双写是最简单的高可用方案:通过两个独立的Prometheus实例同时抓取相同目标,上层通过负载均衡或DNS轮询进行查询分流。
# prometheus-A.yml 与 prometheus-B.yml 配置完全一致
global:
external_labels:
replica: 'A' # B实例改为'B',用于区分数据源
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
关键问题与解决
数据不一致性:由于抓取时间差,两个实例的指标存在微小差异。在 Grafana 中配置查询时,务必使用 max() 或 avg() 聚合函数消除副本差异:
max by (instance) (up{job="api-gateway"})
告警重复:Alertmanager 的 group_by 需包含 replica 标签,并配置 inhibit_rules 抑制重复告警:
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'critical'
equal: ['alertname', 'instance']
适用场景与局限
✅ 适合场景:中小规模集群(target < 500),短期容灾过渡
❌ 致命缺陷:
- 数据无法持久化,本地存储限制在15天(默认)
- 查询无法跨实例聚合,全局视图缺失
- 扩容时线性增加资源浪费
第二阶段:远程存储(Remote Storage)—— 打破数据孤岛
当双写无法满足长期存储和全局查询需求时,引入远程存储成为必然选择。
方案选型对比
| 方案 | 架构复杂度 | 资源成本 | 查询性能 | 适用规模 |
|---|---|---|---|---|
| Thanos | 中 | 低 | 高 | 中大型 |
| VictoriaMetrics | 低 | 极低 | 极高 | 全规模 |
| Cortex/Mimir | 高 | 高 | 中 | 超大规模 |
Thanos 实战配置(主流选择)
Thanos Sidecar 模式是最平滑的演进路径,无需改造现有 Prometheus:
# prometheus 启动参数增加
--storage.tsdb.min-block-duration=2h
--storage.tsdb.max-block-duration=2h
# thanos-sidecar 配置
thanos sidecar \
--tsdb.path=/prometheus/data \
--objstore.config-file=thanos-bucket.yml \
--prometheus.url=http://localhost:9090
thanos-bucket.yml 配置对象存储(以MinIO为例):
type: S3
config:
bucket: "prometheus-metrics"
endpoint: "minio.monitoring.svc.cluster.local:9000"
access_key: "xxx"
secret_key: "xxx"
insecure: true
架构升级要点
- Store Gateway:负责历史数据查询,需独立部署避免影响实时写入
- Compactor:定期压缩块文件,降低存储成本90%以上
- Query Layer:实现全局 PromQL 查询,自动去重(基于
external_labels的replica标签)
第三阶段:联邦集群(Federation)—— 多地域多集群的统一视图
当业务扩展到多可用区、多K8s集群时,分层联邦架构成为唯一选择。
架构拓扑设计
采用 "边缘采集 + 中心聚合" 的两层架构:
[边缘层] [中心层]
Prom-A1 (AZ-1) ──┐
Prom-A2 (AZ-1) ──┤──> Thanos Query ──┐
│ │
Prom-B1 (AZ-2) ──┤ ├──> Global Query
Prom-B2 (AZ-2) ──┘ │
│
[业务K8s-1] ──> Sidecar ─────────────┤
[业务K8s-2] ──> Sidecar ─────────────┘
联邦抓取配置(关键细节)
中心层 Prometheus 仅抓取边缘的聚合指标,避免网络风暴:
scrape_configs:
- job_name: 'federate'
scrape_interval: 15s
honor_labels: true
metrics_path: '/federate'
params:
'match[]':
- '{__name__=~"up|node_cpu_seconds_total|container_memory_usage_bytes"}'
- '{job="api-gateway"}'
static_configs:
- targets:
- 'edge-prometheus-az1:9090'
- 'edge-prometheus-az2:9090'
关键技巧:使用 match[] 过滤器仅拉取关键指标,边缘层保留完整数据用于本地故障排查。
高可用强化策略
- 反亲和性部署:确保同一集群的 Prometheus 实例分布在不同节点/可用区
- 对象存储双活:Thanos 支持多区域对象存储复制,防范单区域故障
- 查询层缓存:部署 Thanos Query Frontend,缓存频繁查询结果,降低后端压力
实战演进路线图
基于团队规模和技术储备,建议按以下路径演进:
| 阶段 | 集群规模 | 关键指标 | 推荐架构 | 切换时机 |
|---|---|---|---|---|
| 起步期 | < 50 nodes | 数据量 < 100GB | 双写 + 本地存储 | 磁盘告警频繁时 |
| 成长期 | 50-200 nodes | 数据量 100GB-1TB | Thanos Sidecar + S3 | 需要跨集群看板时 |
| 成熟期 | > 200 nodes | 多地域部署 | 联邦集群 + Thanos | 单查询超时 > 5s 时 |
避坑指南
- 外部标签冲突:不同集群的
external_labels必须唯一,建议采用cluster+replica组合 - 时间同步:所有 Prometheus 节点必须配置 NTP,时间偏差会导致查询结果错位
- ** Cardinality 爆炸**:联邦层级只保留低基数指标,高基数指标(如
http_request_duration_seconds_bucket)留在边缘层查询
结语:没有银弹,只有权衡
从双写到联邦集群,本质上是在一致性、可用性、分区容错性之间的持续权衡。对于多数中小团队,Thanos Sidecar + 单联邦层已能支撑万级节点规模;而超大规模场景则需要投入Cortex/Mimir的深度定制。
高可用架构不是一次性设计,而是随着业务 pain point 逐步演进的有机体。建议在每个阶段保留降级方案(如双写模式作为Thanos故障时的fallback),确保监控体系自身的可靠性不低于业务系统。