深入剖析 Prometheus 和 Thanos 的工作机制

时间:2025-05-13 07:36:16

作者:禅与计算机程序设计艺术

1.简介

Prometheus 和 Thanos 是目前最热门的开源系统监控解决方案之一。Prometheus 提供了一种基于时序数据库的数据模型,利用用户定义的规则对时间序列数据进行收集、聚合和存储。而 Thanos 提供了一个高可用、可扩展且无限容量的 Prometheus 数据源,可以通过查询 Thanos 查询端并将结果进行归并、压缩和查询等操作。在分布式环境下,Prometheus 有着强大的查询能力和丰富的数据分析工具,而 Thanos 在降低查询延迟方面起到了举足轻重的作用。由于 Thanos 的出现,许多公司纷纷加入 Prometheus 的阵营,围绕 Thanos 提供更加完备的集群架构及支持。
本文首先会以 Prometheus 为例,为读者介绍 Prometheus 的核心概念、基本机制和原理,并结合 Prometheus 的操作场景和源码进行详细的代码讲解;然后,再以 Thanos 为例,对 Thanos 进行介绍和分析,阐述其背后的功能和原理,并展示不同组件之间的交互方式;最后,还会对 Prometheus 和 Thanos 在实际应用中的效果进行比较和探讨。通过本文,读者可以快速掌握 Prometheus 和 Thanos 的工作原理,更好地理解它们的价值及适用场景。

2.基本概念术语说明

Prometheus

监控指标和 Prometheus

Prometheus 使用一个时序数据库(TSDB)来保存所有监控指标数据。每个监控指标都是一个由一组键-值对(labels)和时间戳(timestamp)组成的时间序列(time series)。其中,键-值对为标签(label),用来区分不同的时间序列,比如主机名、IP地址、服务名称或其它任意维度;而时间戳则记录数据点采集的时间。每条时间序列都有一个值为float64类型的样本值。这些样本值可以进行计数、测量值或者计费量等任何可以测量的东西。

Metric_name{label1="value1", label2="value2"} value timestamp
  • 1

每个时间序列中的多个数据点可以被视为一个样本序列(sample stream)。样本序列由多个相同标签的指标组成,并且具有相似的时间戳。例如,一个节点的CPU利用率可以作为一个名为“node_cpu”的监控指标,其标签包括“mode”(内核模式、用户模式或空闲状态)、“hostname”(机器名)、“instance”(节点的实例ID)和其它一些描述性信息。那么,这个时间序列可能的样本序列示例如下:

node_cpu{mode="idle", hostname="machineA", instance="server01:9100"} 97 1546392230100
node_cpu{mode="user", hostname="machineB", instance="server02:9100"} 65 1546392230100
...
  • 1
  • 2
  • 3

上面的示例中,服务器01的CPU处于空闲状态,利用率为97%;服务器02的CPU处于用户态,利用率为65%。这两个样本共享相同的时间戳1546392230100。在 Prometheus 中,同类指标的集合称为样本集(sample set)。样本集表示一个时刻的一组时间序列。

模型

Prometheus 定义了一套数据模型来存储和组织监控指标。其数据模型由以下几个主要对象构成:

  • Targets - 监控目标
  • Rules - 报警规则
  • Alertmanager - 处理 alerts 的服务
  • Service Discovery - 服务发现
  • TSDB - 时序数据库
Targets

Targets 表示要抓取的监控目标,它包含了 target 名称、URL、端口、类型、用户名和密码等元信息。Prometheus 通过配置目标列表来决定哪些目标需要被抓取,以及从目标那里拉取哪些指标。

Rules

Rules 表示 Prometheus 如何从抓取到的监控数据生成 alerts,它包含了 alerting rule 定义和 alert 消息模板。当某一条监控指标满足报警条件时,Prometheus 将根据 rules 生成 alerts,并把 alerts 发送给指定的 alert manager 来处理。

Alert Manager

Alert Manager 是 Prometheus 的组件之一,用于管理 alerts。它维护一个队列,并按 severity 分别发送 alerts。Alert Manager 可以接收来自 Prometheus 的 alerts、外部脚本产生的 alerts 或 webhooks 。它还可以设置 silences 来忽略某些 alerts 。

Service Discovery

Service Discovery 是 Prometheus 中的插件模块,允许 Prometheus 从不同的服务发现系统中动态发现目标。当前实现了 Consul 和 DNS 支持。

TSDB

Prometheus 使用自己的时序数据库(Time Series Database,缩写为TSDB)来存储和检索监控数据。Prometheus 的 TSDB 支持 PromQL ,一个强大的查询语言。Prometheus 的 TSDB 不是唯一可选方案,还有 InfluxDB、Graphite 和 OpenTSDB 等也很流行。

模型关系图

下图展示了 Prometheus 数据模型各个对象的关联关系。

存储格式

Prometheus 的时序数据采用的是 Prometheus 的标准 TSDB 格式。每个时间序列都以独一无二的标识符(即哈希值)作为其标识,并将相关的数据(包括样本值、标签和时间戳)保存在一起。同时,每个时间序列都以时间戳对齐的方式组织起来,这样可以方便地查询。其数据组织形式如上所示。

一致性保证

Prometheus 使用远程读取(remote reads)和远程写入(remote writes)来确保一致性。Remote read 是为了执行实时的查询而做的优化。Prometheus 将在本地磁盘中缓存少量的数据,以便尽快响应请求。Remote write 是为了使集群间的复制过程更高效而设计的。当数据通过 remote write 传入时,Prometheus 会先写入自己的本地 TSDB,然后异步地将数据同步到其他成员节点上。

Thanos

Thanos 是一种高可用、可扩展且无限容量的 Prometheus 数据源。通过利用多个 Prometheus 集群或其他数据源的查询接口来实现快速、透明地查询整个集群的所有监控数据。Thanos 可自动将多个 Prometheus 集群的数据汇总到单个可查询的 TSDB 中,并提供全局范围的查询视图,实现对所有 Prometheus 集群的透明查询。Thanos 的主要功能包括:

  1. 降低查询延迟
  2. 节省存储空间
  3. 提供多个数据源的聚合视图
    Thanos 由以下三个组件组成:
  4. Querier - 用于查询和返回聚合数据的 HTTP 服务
  5. Store Gateway - 用于查询底层存储(Object Stores 和 Prometheus 集群)的 gRPC 服务
  6. Object Store - 对象存储抽象,如 Amazon S3、Google Cloud Storage 或 Azure Blob Storage

Querier

Querier 是 Thanos 组件之一,用于处理客户端请求并返回聚合数据的 HTTP 服务。Querier 可以运行在 Kubernetes 中、本地部署、物理机或云平台上。Querier 首先解析客户端请求,检查是否存在需要聚合的数据,如果需要的话,它将向 Store Gateway 发出查询请求。Store Gateway 根据查询参数和底层数据源确定要访问的位置,然后将查询请求转发到相应的数据源。

  1. 查询时序数据:Querier 会将查询请求转换为普通的 PromQL 查询,并在本地 TSDB 中执行。
  2. 查询聚合数据:如果本地没有足够的样本数据来计算聚合数据,Querier 将向 Store Gateway 发出聚合查询请求。
  3. 返回结果:Querier 将聚合数据合并后返回给客户端。

Store Gateway

Store Gateway 是 Thanos 组件之一,用于查询底层存储(Object Stores 和 Prometheus 集群)的 gRPC 服务。Prometheus 提供多个 API ,包括 remote write、remote read、query、series 等。Store Gateway 负责将 Prometheus API 映射到对象存储的 API,并屏蔽底层数据源的细节。

  1. Query:Query 请求被转换为 Prometheus 查询,并发送到对应的 Prometheus 集群中。
  2. Remote Read:Remote Read 请求被转换为 Prometheus 查询,并发送到 Prometheus 集群中。
  3. Remote Write:Remote Write 请求直接被转发到 Object Store。

对象存储抽象

Thanos 提供了一种统一的接口规范,允许各种对象存储作为底层存储,例如 Amazon S3、GCS 或 Azure Blob Storage。这种对象存储抽象允许 Thanos 用户在不了解底层存储的情况下,使用标准化的接口管理数据。

Prometheus 应用场景与原理

3.核心算法原理和具体操作步骤以及数学公式讲解

1.查询请求流程

Prometheus 是时序数据库,所以其数据模型结构为 time series。但是一般情况下我们习惯于使用标签进行分类,因此 Prometheus 也提供了丰富的过滤方式,能够按照标签来查询特定的数据。
当 Prometheus 接收到查询请求时,首先判断是否需要对请求进行预处理,如对关键字进行拆分。然后将请求传递给引擎进行查询,并返回结果。引擎会解析查询语句,获取标签信息,查找缓存,从磁盘或远端读取索引文件,读取时间序列数据,合并结果,输出。
Prometheus 查询流程:

  1. 如果 Prometheus 需要对查询字符串进行拆分,将其拆分为不同的子句。
  2. 遍历所有的时间序列,并对其标签信息和数据进行匹配。如果标签不完全匹配,则跳过该时间序列。
  3. 对匹配的标签进行归类统计,对匹配的时间序列进行排序,并分配序列编号。
  4. 如果查询语句含有 aggregator 函数,则对数据进行聚合,并对聚合结果进行排序。
  5. 根据配置的查询步长,对结果集进行截断,输出最终结果。

2.数据写入流程

Prometheus 的数据写入流程分为两步:接收写入请求 -> 数据持久化。

  1. Prometheus 接收到数据写入请求,首先会对其进行预处理。对于有效数据,Prometheus 会对其进行采样,并对采样点的时间戳进行排序,分配序列号,并将采样数据与序列号进行绑定。对于无效数据(比如样本数据不符合格式要求),Prometheus 会直接丢弃。
  2. Prometheus 对已收到的数据进行持久化。对于接收到的有效数据,Prometheus 会把采样数据和序列号写入内存中的临时内存表中。对于接收到的无效数据,Prometheus 会直接丢弃。当内存临时内存表大小达到一定阈值,或指定的时间段后,Prometheus 会将数据批量写入到磁盘的内存表中。
  3. Prometheus 检查本地磁盘中是否有待写入的数据,并写入相应的文件中。对于接收到的有效数据,Prometheus 会把采样数据和序列号写入到磁盘的内存表中。对于接收到的无效数据,Prometheus 会直接丢弃。

3.定时任务

Prometheus 的定时任务主要有两个:

  • 恢复数据(全局和局部):Prometheus 会周期性地扫描本地磁盘上的数据,找出尚未持久化的临时内存表中的数据,并将其持久化到磁盘。
  • 清除过期数据:Prometheus 会定期清除过期的数据,默认保留最近的 2 小时的数据。

4.数据压缩

Prometheus 支持对存储的数据进行压缩,提高查询效率。通过配置参数 enableCompression=true,Prometheus 开启压缩功能。
数据压缩流程:

  • Prometheus 启动时,加载持久化数据。
  • 当新的数据点进入内存时,如果 enableCompression=true,Prometheus 会对数据进行压缩。
  • 当数据达到一定数量后,Prometheus 会对数据进行整理。
  • 压缩后的数据只会在下一次写入磁盘的时候才会被压缩,不会影响原始数据。

5.数据删除

Prometheus 支持按时间和标签来删除数据。通过配置参数 delete_overlapping_data=true,Prometheus 开启删除重叠数据功能。
删除数据流程:

  • Prometheus 启动时,加载持久化数据。
  • 当新的数据点进入内存时,如果 enableDelete=true,Prometheus 会对数据进行删除。
  • 对于给定的时间窗口和标签,Prometheus 会找到所有与该标签匹配的时间序列。
  • 如果某个时间序列的最新数据早于指定的时间,则会将该时间序列标记为过期,下次写入数据时,Prometheus 会自动覆盖该时间序列。

6.热点问题

随着时代的进步,互联网业务的发展,大规模集群的出现,监控数据越来越多。但是,监控数据也是有限的资源,随着集群的增大,各种监控项之间的数据可能产生碎片。也就是说,不同监控项的数据可能会出现竞争关系,最终导致查询性能受损。
为了缓解这一问题,Prometheus 提供了去重策略,支持两种去重策略:时间窗口和全量去重。

  • 时间窗口:以固定的时间窗口作为单位,对时间窗口内的数据进行去重,并将去重后的数据写入新的时间序列。
  • 全量去重:每隔一段时间,Prometheus 会对全部数据进行全量去重,重新构建索引文件。
    默认情况下,Prometheus 使用时间窗口去重。

7.告警

Prometheus 支持基于PromQL定义的规则,将指定的表达式的值与预设的阈值进行比较,触发相应的告警。如果规则触发告警,Prometheus 会向 AlertManager 发送告警信息。
Prometheus 告警流程:

  1. Prometheus 从 AlertManager 获取当前正在处理的告警信息。
  2. Prometheus 检查当前要处理的告警规则,并对每个规则进行评估。
  3. 如果满足告警条件,Prometheus 就会向 AlertManager 发送告�警信息。
  4. AlertManager 判断告警信息是否已经存在,如果不存在,就将告警信息保存到数据库中。
  5. 如果告警信息已经存在,则会进行合并,更新告警消息等操作。

8.架构

Prometheus 的架构分为四层:

  1. Core:核心组件,包括:Target、Rule、Alertmanager、Service Discovery、TSDB。
  2. Storage:存储组件,包含:本地磁盘、内存、远程存储(如 AWS S3)。
  3. Compute:计算组件,包括:Aggregators、Query language(PromQL)。
  4. APIs and Interfaces:API 接口层,包括:HTTP、gRPC、Java Client、Python Client。

查询路由

Prometheus 的查询路由机制帮助 Prometheus 自动将查询请求路由到相应的目标。当 Prometheus 接收到客户端的查询请求时,它首先会解析查询语句,根据规则选择目标,并将请求发送给相应的组件。查询路由的过程如下:

  1. Prometheus 接收到客户端请求,并解析查询语句。
  2. Prometheus 根据查询语句中的标签,确定应该将查询请求路由到哪个 Target。
  3. Prometheus 根据查询语句中的时间范围,选择需要的数据。
  4. Prometheus 将数据发送给相应的组件进行处理。
  5. 根据查询请求的目标,Prometheus 会将查询结果返回给客户端。
    Prometheus 的查询路由过程如下图所示。

Querier

Querier 是 Prometheus 架构中最重要的组件之一,负责查询处理。Querier 负责接收 Prometheus 的查询请求并返回数据。其核心职责包括:

  1. 查询时序数据:Querier 接收 Prometheus 的查询请求并执行查询。
  2. 查询聚合数据:Querier 基于本地数据计算聚合数据。
  3. 返回结果:Querier 返回查询结果。
    Querier 组件如下图所示。

查询时序数据

Querier 接收 Prometheus 的查询请求并执行查询。Prometheus 提供的 PromQL 是一种声明性的语言,使用直观的语法来表示查询逻辑。PromQL 查询语言封装了对时序数据的复杂查询逻辑。
Promethus 将 PromQL 语句解析为一个表达式树,然后遍历表达式树。对于每一个表达式节点,它都会调用执行器(executor)函数。对于查询语句中包含的每个表达式,执行器函数都会执行查询。对于表达式树中的每个叶子节点,执行器函数会根据节点的信息找到相应的样本数据并进行处理。
执行器函数会首先检查是否有缓存命中。如果命中,执行器会直接返回缓存中的数据。否则,执行器会使用 TSDB 接口来查询时序数据。TSDB 接口会根据表达式中的时间范围和标签信息,找到匹配的时序数据,并将数据组合在一起,并进行聚合。执行器会将结果缓存起来,并返回给 Querier。

查询聚合数据

Querier 根据本地数据计算聚合数据。当本地没有足够的数据来计算某个聚合函数时,Prometheus 会发起远程查询请求,将聚合请求路由到 Store Gateway。Querier 会从本地数据中查询必要的数据,并进行聚合。

返回结果

Querier 返回查询结果。Prometheus 提供多个接口,包括 HTTP API、gRPC API、Python API 和 Java API,Querier 会根据客户端的请求协议,选择相应的接口,并将结果返回给客户端。

Rule

Rule 组件是 Prometheus 架构中的核心组件,负责配置规则和报警处理。其核心职责包括:

  1. 配置规则:Prometheus 接收 Alertmanager 的配置,并将其解析为规则。
  2. 评估规则:Prometheus 根据规则匹配时间序列,并评估其当前值是否超过阈值。
  3. 发送告警:如果规则触发告警,Prometheus 会向 AlertManager 发送告警信息。
    Rule 组件如下图所示。

配置规则

Prometheus 接收 Alertmanager 的配置,并将其解析为规则。配置规则的过程如下:

  1. Prometheus 接收到来自 Alertmanager 的配置,并将其解析为内部结构。
  2. Prometheus 将规则保存到规则存储中。
  3. Prometheus 立即生效规则。

评估规则

Prometheus 根据规则匹配时间序列,并评估其当前值是否超过阈值。评估规则的过程如下:

  1. Prometheus 收到查询请求,并解析查询语句。
  2. Prometheus 查找匹配的规则,并评估它们的条件表达式。
  3. 如果条件表达式为真,则 Prometheus 触发告警。
  4. Prometheus 向 Alertmanager 发送告警信息。

发送告警

如果规则触发告警,Prometheus 会向 AlertManager 发送告警信息。告警信息包含了通知渠道,告警消息,告警状态,告警级别,告警次数等信息。
Prometheus 的告警处理流程如下图所示。

Store Gateway

Store Gateway 组件是 Prometheus 架构中的关键组件,用于查询底层存储的时序数据。其核心职责包括:

  1. 查询时序数据:Store Gateway 接收 Prometheus 的查询请求,并执行查询。
  2. 查询聚合数据:Store Gateway 基于本地数据计算聚合数据。
  3. 返回结果:Store Gateway 返回查询结果。
    Store Gateway 组件如下图所示。

查询时序数据

Store Gateway 接收 Prometheus 的查询请求,并执行查询。Prometheus 提供的 PromQL 是一种声明性的语言,使用直观的语法来表示查询逻辑。PromQL 查询语言封装了对时序数据的复杂查询逻辑。
Promethus 将 PromQL 语句解析为一个表达式树,然后遍历表达式树。对于每一个表达式节点,它都会调用执行器(executor)函数。对于查询语句中包含的每个表达式,执行器函数都会执行查询。对于表达式树中的每个叶子节点,执行器函数会根据节点的信息找到相应的样本数据并进行处理。
执行器函数会首先检查是否有缓存命中。如果命中,执行器会直接返回缓存中的数据。否则,执行器会使用 TSDB 接口来查询时序数据。TSDB 接口会根据表达式中的时间范围和标签信息,找到匹配的时序数据,并将数据组合在一起,并进行聚合。执行器会将结果缓存起来,并返回给 Store Gateway。

查询聚合数据

Store Gateway 根据本地数据计算聚合数据。当本地没有足够的数据来计算某个聚合函数时,Prometheus 会发起远程查询请求,将聚合请求路由到 Store Gateway。Store Gateway 会从本地数据中查询必要的数据,并进行聚合。

返回结果

Store Gateway 返回查询结果。Prometheus 提供多个接口,包括 HTTP API、gRPC API、Python API 和 Java API,Store Gateway 会根据客户端的请求协议,选择相应的接口,并将结果返回给客户端。

TSDB

TSDB 组件是 Prometheus 架构的基础组件。TSDB 是 Prometheus 用于存储和检索时序数据的组件。其主要功能有:

  1. 时序数据存储:TSDB 会存储时序数据。
  2. 时序数据查询:TSDB 具有灵活的查询语法,能够支持复杂的查询和聚合操作。
  3. 高效压缩:TSDB 支持高效压缩,可以减小存储空间占用。
    TSDB 组件如下图所示。

时序数据存储

时序数据存储。TSDB 以键-值对的形式存储时序数据。键是时间戳和标签的组合,值是浮点数。TSDB 可以对时序数据进行快速插入、删除、更新、聚合等操作。时序数据也支持按时间戳和标签进行索引,快速检索。

时序数据查询

时序数据查询。TSDB 具有灵活的查询语法,能够支持复杂的查询和聚合操作。TSDB 提供了多种数据查询方式,如原始数据查询、范围查询、聚合查询、多种聚合函数等。

高效压缩

TSDB 支持高效压缩。TSDB 会将采样的数据按时间段划分,并对每个时间段内的数据进行统计和编码,生成紧凑的数据。对相同的时间戳的样本,TSDB 只需记录第一个样本的标签和值,并记录相应的时间戳即可。

9.性能调优

Prometheus 是一个分布式系统,它内部有多个组件,它们之间经常发生通信和协作。因此,性能调优往往是优化系统整体性能的重要手段。下面我们讨论一下 Prometheus 的性能调优方法。

1.组件分离

Prometheus 具有高度可伸缩性,因此建议将组件分离。一般来说,建议将抓取组件和查询组件分离,并使用分布式集群来部署。
抓取组件负责收集数据,并将数据持久化到本地磁盘或远程存储。查询组件负责处理客户端的查询请求,并返回结果。

2.压缩优化

Prometheus 具有压缩功能,可以减小存储空间占用。但默认情况下,压缩功能是关闭的。建议打开压缩功能,并调整参数,以获得最佳压缩比。

3.查询优化

Prometheus 具有灵活的查询语法,支持多种聚合函数。建议调整查询语句的参数,以获得更准确和有效的结果。

4.规则优化

Prometheus 具备强大的告警规则,它可以在规则触发时向 AlertManager 发送告警信息。建议根据情况优化规则,降低误报率和漏报率。

5.集群规模

Prometheus 是分布式系统,它可以使用分布式集群来扩展性能。建议集群规模不要太大,否则会影响查询性能。

6.监控指标

Prometheus 提供丰富的监控指标,可以让管理员了解系统的运行状况。建议监控 CPU、内存、网络等关键指标,并建立警报规则,及时发现异常。

7.预警策略

Prometheus 提供的规则可以让管理员定义预警策略。建议根据业务特点,设置不同的预警策略,提升系统的容错能力。

10.总结

本文介绍了 Prometheus 和 Thanos 的工作原理,并通过 Prometheus 的工作原理,带领大家快速理解 Prometheus 的工作机制。希望通过阅读本文,读者能够了解 Prometheus 和 Thanos 的工作原理,并有能力基于 Prometheus 实现系统监控。