基于 Thanos 的 Prometheus 高可用与无限存储架构深度剖析

本文面向正在或计划构建大规模监控系统的中高级工程师与架构师。我们将从 Prometheus 在规模化场景下遇到的真实困境出发,深入剖析 Thanos 如何基于计算机科学的基础原理(如 LSM-Tree、Sidecar 模式)构建一个逻辑上无限、高可用的全局监控视图。文章将穿透概念表层,直达架构设计的核心权衡、关键模块的实现细节,并给出可落地的分阶段演进路线,帮助你构建一个能够支撑企业未来数年发展的监控基础设施。

现象与问题背景

Prometheus 已成为云原生监控领域的事实标准。其强大的 Pull 模型、多维度标签系统以及表现力极强的 PromQL 查询语言,使其在单体或小规模集群环境中表现出色。然而,当企业业务扩展,基础设施规模(例如 Kubernetes 集群数量)增长到一定程度时,原生的 Prometheus 架构会暴露出几个难以回避的瓶颈:

  • 有限的存储周期: Prometheus 的 TSDB (Time Series Database) 被设计为在本地磁盘上进行高效读写,而非长期存储。为了控制磁盘使用量,工程师通常只会保留 15-30 天的数据。当需要进行年度容量规划或长期趋势分析时,这便成了致命短板。
  • 数据孤岛与全局视图缺失: 在多 K8s 集群、多数据中心的环境下,标准做法是在每个集群内部署一套独立的 Prometheus。这导致监控数据被打散在各个“孤岛”中。当业务需要跨集群进行关联分析(例如,查询某个全局服务在所有区域的总 QPS),运维人员必须手动向多个 Prometheus 端点执行查询并合并结果,这不仅效率低下,而且极易出错。
  • 单点故障与高可用难题: 单点的 Prometheus Server 意味着一旦其所在节点或 Pod 发生故障,该集群的监控将完全中断。虽然可以部署两套完全相同的 Prometheus 实例(HA Pair)来抓取相同的 Targets,但如何对查询流量进行负载均衡、如何在查询时对来自两个副本的重复数据进行去重,原生 Prometheus 并未提供优雅的解决方案。
  • 查询性能瓶颈: 随着数据量的增长和查询时间范围的拉长,单个 Prometheus 实例的查询性能会显著下降。尤其是在执行高基数(high cardinality)聚合查询时,CPU 和内存消耗会急剧上升,甚至导致 OOM (Out of Memory)。

这些问题并非 Prometheus 的设计缺陷,而是其核心定位所致——它是一个极其优秀的实时监控和告警系统,但并非一个分布式、可无限扩展的长期存储解决方案。Thanos 的出现,正是为了在不侵入 Prometheus 内核的前提下,优雅地解决上述所有问题。

关键原理拆解

Thanos 的设计哲学是“化整为零,再聚沙成塔”,它将一个庞大的、集中式的监控平台拆解为一系列职责单一、可独立扩展的组件。其背后依赖于几个关键的计算机科学与分布式系统原理。

(教授声音)

  • 基于 LSM-Tree 的分层存储思想: Prometheus 的 TSDB 本身就借鉴了 Log-Structured Merge-Tree 的思想。新写入的数据首先存在于内存中的 Head Block,这是一个可变的读写区域。当数据达到一定量(默认为 2 小时)后,会被持久化到磁盘上,成为一个不可变的 Block 文件。Thanos 将这一思想延伸到了极致:它将本地磁盘视为“近期数据”的缓存层,而将廉价、高持久性的对象存储(如 S3, GCS, MinIO)视为“远期数据”的最终归宿。本地 Prometheus 只负责短期、高速的读写,而 Sidecar 组件则像一个异步的“归档工”,定期将本地磁盘上已经固化的 Block 文件上传到对象存储中。这形成了一个从内存 -> 本地磁盘 -> 对象存储的多级分层存储体系,兼顾了读写性能与存储成本。
  • Sidecar 模式的无侵入扩展: Thanos 对 Prometheus 的集成堪称非侵入式设计的典范。它没有 Fork Prometheus 的代码,而是通过一个名为 `thanos sidecar` 的独立进程与 Prometheus Pod 部署在一起。这个 Sidecar 进程通过共享的 EmptyDir Volume 读取 Prometheus 的数据目录,并对外提供一个 gRPC Store API。这种模式将“长期存储”的逻辑与“核心监控”的逻辑完全解耦,使得 Prometheus 和 Thanos 可以独立升级和维护,极大地增强了系统的灵活性和健壮性。
  • 分布式系统的“查询下推”与“结果聚合”: Thanos 的全局查询视图并非通过将所有数据集中存储在一处来实现的。恰恰相反,数据仍然是物理分散的。当一个全局查询请求到达 Thanos Query 组件时,它会扮演一个查询协调者的角色。它首先通过服务发现机制找到所有提供 Store API 的数据源(包括各个 Prometheus 的 Sidecar 和访问对象存储的 Store Gateway),然后将原始查询“下推”到所有相关的数据源并行执行。每个数据源在本地完成数据过滤和初步聚合后,将结果返回给 Query 组件。最后,Query 组件对来自不同数据源的结果进行最终的合并(Merge)和去重(Deduplication),从而呈现给用户一个统一、完整的视图。这是一种典型的 Scatter-Gather 计算模式。

系统架构总览

一个完整的 Thanos 部署方案,通常由以下几个核心组件构成,它们协同工作,共同组成一个逻辑上统一的监控平台:

数据源层:

  • Prometheus + Sidecar: 这是数据产生的源头。每个 Prometheus 实例旁都伴随着一个 Sidecar。Sidecar 有两个核心职责:1) 将 Prometheus 本地生成的不可变数据块(Blocks)上传到对象存储;2) 对外暴露 Store API,使得 Thanos Query 可以直接查询该 Prometheus 实例持有的近期数据(通常是 2-6 小时内的热数据)。

查询聚合层:

  • Query / Querier: 这是用户查询的统一入口。它本身不存储任何数据,而是实现了 Store API 的“客户端”。它会发现网络中所有可用的 Store API 服务端(Sidecars 和 Store Gateways),根据查询的时间范围,智能地将请求路由到相应的数据源,并聚合返回的结果。
  • Query Frontend (可选): 这是一个位于用户和 Query 之间的高性能代理。它提供了诸如查询缓存、长查询拆分、并发查询限制等高级功能,能显著提升大规模查询场景下的系统性能和稳定性。

长期存储与访问层:

  • Object Storage: 系统的“底座”,如 AWS S3, Google Cloud Storage, Azure Blob Storage 或自建的 MinIO。所有 Prometheus 的历史数据块最终都存储在这里,提供了几乎无限的存储容量和极高的数据持久性。
  • Store Gateway: 这个组件是对象存储的“代言人”。它会监控对象存储中的数据块,并将其元数据(索引)缓存在本地。它同样实现了 Store API,使得 Thanos Query 能够查询存储在对象存储中的全部历史数据。

后台维护层:

  • Compact: 负责对对象存储中的数据进行后台维护。主要工作包括:1) 合并(Compaction):将小的数据块合并成更大的块,减少索引大小,提升查询效率。2) 降采样(Downsampling):将高精度数据聚合成低精度数据(例如,将原始 15 秒间隔的数据降采样为 5 分钟或 1 小时间隔的聚合数据),在保证长期趋势分析能力的同时,大幅降低存储成本和查询延迟。3) 数据保留(Retention):根据配置策略,删除过期的数据。
  • Ruler: 提供了全局告警规则和记录规则的评估能力。它会定期向 Thanos Query 发起查询,对全局数据进行评估,从而可以在一个集中的地方管理跨集群的告警逻辑。

一个典型的查询流程是:用户的 PromQL 请求发送给 Query Frontend,后者转发给 Query。Query 组件解析查询的时间范围,将针对近期数据的查询部分发给各个 Prometheus 的 Sidecar,将针对历史数据的查询部分发给 Store Gateway。Sidecar 和 Store Gateway 并行处理请求,返回各自的结果。Query 组件将这些部分结果合并、排序、去重后,返回给 Query Frontend,最终呈现给用户。

核心模块设计与实现

(极客声音)

理论听起来很美好,但魔鬼在细节里。我们来看几个关键点的实现和配置,这些地方是新手最容易踩坑的。

Sidecar 与 Prometheus 的协同

Sidecar 和 Prometheus 之间不是通过网络通信,而是通过共享文件系统。在 Kubernetes 中,这通常是一个 `emptyDir` volume。Prometheus 按照其 2 小时一个 block 的节奏生成数据,一旦一个 block 变得不可变,Sidecar 就能感知到,并开始上传。这里的关键配置是 Prometheus 的 `external_labels`。你必须为每个 Prometheus 实例配置一组全局唯一的标签,Thanos Query 会用这组标签来识别和去重数据。


# In prometheus.yaml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    cluster: 'k8s-prod-cluster-1'
    replica: '0' # For HA, the other instance would be '1'

Sidecar 的启动参数则需要指定对象存储的凭证和桶信息。一个常见的坑是网络策略(Network Policy)或防火墙忘了给 Sidecar 开通访问对象存储的出向流量,导致上传失败,日志里会报 `bucket operation` 相关的错误。

Query 的数据去重(Deduplication)

当你为了高可用部署了两套完全一样的 Prometheus(一个 `replica: ‘0’`,一个 `replica: ‘1’`)时,它们会抓取完全相同的数据。当 Thanos Query 同时从这两个 Sidecar 查询时,它会收到两份一模一样的时间序列,只是 `replica` 标签不同。Query 组件的 `deduplication` 功能就是为此而生。

启动 Query 时,你需要通过 `–query.replica-label=replica` 参数告诉它用哪个标签来识别副本。在处理查询结果时,Query 会对具有完全相同标签集(除了 `replica` 标签)的时间序列进行合并,并优先选择标签值较小(按字典序)的副本的数据点。这个看似简单的去重逻辑,是实现 Prometheus 无缝 HA 的核心所在。

Compact 的降采样(Downsampling)

这可能是 Thanos 最有价值但也最复杂的特性。原始数据通常是秒级精度,存几年下来,成本和查询性能都扛不住。降采样就是救星。Compact 组件可以配置多个降采样级别。例如:


# Compactor arguments
- --data-dir=/var/thanos/compact
- --objstore.config-file=/etc/config/thanos.yaml
- --wait
- --downsampling.resolution=5m  # First level: downsample to 5min
- --downsampling.resolution=1h   # Second level: downsample to 1h
- --retention.resolution-raw=30d # Keep raw data for 30 days
- --retention.resolution-5m=1y   # Keep 5min data for 1 year
- --retention.resolution-1h=5y   # Keep 1h data for 5 years

这个配置意味着:

  • 原始数据(raw)保留 30 天。
  • 超过 30 天的原始数据会被降采样为 5 分钟间隔的数据,这份 5 分钟粒度的数据会保留 1 年。
  • 超过 1 年的 5 分钟数据会被进一步降采样为 1 小时间隔的数据,并保留 5 年。

Thanos Query 在查询时是足够智能的。当你的查询 `step`(步长)大于等于 1 小时,它会自动选择查询 1 小时降采样的数据,如果 `step` 在 5 分钟到 1 小时之间,它会用 5 分钟的数据,否则用原始数据。这个机制对用户是透明的,但对查询性能的提升是数量级的。一个巨大的坑点是: 降采样配置一旦设定并运行,后续修改会非常麻烦,甚至需要手动清理对象存储中的数据。所以,在项目初期就必须规划好降采样和保留策略。

性能优化与高可用设计

一套生产可用的 Thanos 系统,除了功能正确,还必须考虑性能和可用性。

查询性能优化

  • 部署 Query Frontend: 别犹豫,直接上。它的结果缓存能挡住大量重复的 Dashboard 刷新请求。查询拆分功能可以把一个跨度一年的查询,拆成 365 个一天的小查询并行执行,避免单个 Query 组件因处理大查询而 OOM。
  • Store Gateway 的索引缓存: Store Gateway 启动时需要从对象存储下载数据块的元数据和索引。这个过程可能很慢且消耗大量内存。务必给 Store Gateway 配置足够的本地磁盘空间(`–data-dir`)和内存。它会将索引缓存到本地,后续启动和查询会快很多。还可以通过 `–index-cache-size` 参数精细控制内存中的索引缓存大小。
  • 垂直与水平扩展: Query 和 Store Gateway 都是可以水平扩展的。当查询并发量大时,增加 Query 的副本数。当历史数据量巨大,单个 Store Gateway 加载索引吃力时,可以增加 Store Gateway 的副本数,并利用其分片(Sharding)功能,让每个副本只负责一部分数据块。

高可用性设计

  • 组件无状态化: Thanos 的大部分组件(Query, Ruler, Sidecar, Store Gateway)都是基本无状态的,可以随时启动多个副本进行负载均衡和故障转移。
  • Compact 的单例运行: Compact 组件是个例外。它是有状态的,并且同一时间只能有一个实例在对对象存储进行操作,否则可能导致数据损坏。在 Kubernetes 中,通常使用 StatefulSet 并将副本数设为 1 来保证其单例性。新版本的 Thanos 提供了`compactor.sharding-config-file`,可以支持多个 Compactor 实例对不同的外部标签组进行分片处理,但这属于更高级的玩法。
  • Store Gateway 的分片高可用: 如果你对 Store Gateway 做了分片,例如3个副本,每个负责总数据的1/3。当一个副本挂掉时,那1/3的历史数据就查不到了。为了解决这个问题,可以引入 Hashring 机制,让每个数据分片都有多个副本(不同的 Store Gateway 实例)来提供服务。
  • 依赖的健壮性: Thanos 强依赖对象存储和服务发现(如 DNS 或 Consul)。确保你的对象存储有跨可用区(AZ)的容灾能力,服务发现机制也要做到高可用。

架构演进与落地路径

直接一步到位部署全套 Thanos 对于很多团队来说既不现实也无必要。一个更务实的演进路径如下:

第一阶段:解决长期存储问题

这是最常见的起点。你已经有一个或多个 Prometheus 实例,但苦于数据无法长期保留。此时,你只需要:

  1. 部署一个对象存储服务(例如 MinIO)。
  2. 为每个现有的 Prometheus 部署一个 Sidecar,配置好对象存储连接,开始上传数据。
  3. 部署一套 Store Gateway 和 Compact 组件,指向同一个对象存储桶。
  4. 此时,你可以通过 Grafana 直接添加 Store Gateway 作为数据源,来查询历史数据。这个阶段你甚至都不需要部署 Thanos Query。

价值: 以最小的改动解决了 Prometheus 数据长期存储的核心痛点。

第二阶段:实现全局查询视图

当你的 Prometheus 实例变多,跨实例查询的需求变得强烈时,就该引入 Thanos Query 了。

  1. 部署 Thanos Query 组件。
  2. 配置 Query 的服务发现,使其能够找到所有的 Sidecar 和 Store Gateway 实例的 Store API 端点。在 K8s 中,这通常通过创建一个 Headless Service 来实现。
  3. 将 Grafana 的数据源从原来的各个 Prometheus 或 Store Gateway,统一切换到这个新的 Thanos Query 端点。

价值: 提供单一入口,屏蔽了底层数据源的复杂性,运维和开发人员拥有了全局统一的监控视图。

第三阶段:完善高可用与性能

当系统规模进一步扩大,稳定性和性能成为主要矛盾时,就需要进行加固。

  1. 为核心业务集群的 Prometheus 部署 HA Pair(即两个抓取相同目标的实例),并为它们配置不同的 `replica` 外部标签。在 Thanos Query 上启用去重功能。
  2. 在 Thanos Query 前面部署 Query Frontend,开启缓存和查询切分。
  3. 为所有无状态组件(Query, Store Gateway)配置多个副本和 HPA (Horizontal Pod Autoscaler)。
  4. 仔细规划并实施 Compact 的降采样和保留策略,以控制成本和查询性能。

价值: 建成一个生产级、高可用的监控平台,能够抵御单点故障,并为大规模查询提供性能保障。

通过这样的分阶段演进,团队可以根据业务的实际需求和痛点,逐步、平滑地从一个简单的 Prometheus 部署过渡到一个功能强大、可无限扩展的云原生监控体系。这不仅降低了初期的实施风险,也让团队有时间逐步消化和掌握 Thanos 复杂的组件生态。

延伸阅读与相关资源

  • 想系统性规划股票、期货、外汇或数字币等多资产的交易系统建设,可以参考我们的
    交易系统整体解决方案
  • 如果你正在评估撮合引擎、风控系统、清结算、账户体系等模块的落地方式,可以浏览
    产品与服务
    中关于交易系统搭建与定制开发的介绍。
  • 需要针对现有架构做评估、重构或从零规划,可以通过
    联系我们
    和架构顾问沟通细节,获取定制化的技术方案建议。
滚动至顶部