Prometheus Agent 模式介绍:一种高效、云原生的指标转发方式

2021 年 11 月 16 日作者 Bartlomiej Plotka (@bwplotka)

Bartek Płotka 自 2019 年起担任 Prometheus 维护者,并在 Red Hat 担任首席软件工程师。他是 CNCF Thanos 项目的合著者。他是 CNCF 大使,并担任 CNCF TAG Observability 的技术主管。业余时间,他与 O'Reilly 合作撰写一本名为《高效 Go》的书。以上观点仅代表我个人!

我个人对 Prometheus 项目的热爱,以及我加入这个团队的众多原因之一,是它对项目目标的专注。Prometheus 始终致力于在提供实用、可靠、经济但又极其宝贵的基于指标的监控方面不断突破界限。Prometheus 超稳定且强大的 API、查询语言和集成协议(例如 Remote Write 和 OpenMetrics )使得 Cloud Native Computing Foundation (CNCF) 指标生态系统能够在这些坚实的基础上蓬勃发展。其结果是取得了令人瞩目的成就。

  • 我们可以看到社区提供了各种导出器,用于获取几乎所有内容的指标,例如 容器 eBPF Minecraft 服务器统计信息 ,甚至 园艺中植物的健康状况 
  • 如今,大多数人期望云原生软件都具有 Prometheus 可以抓取的 HTTP/HTTPS /metrics 端点。这是 Google 在内部秘密开发并在 Prometheus 项目的全球推广下普及的概念。
  • 可观测性范式发生了转变。我们看到 SRE 和开发人员从第一天起就严重依赖指标,这提高了软件的弹性、可调试性和数据驱动的决策能力!

最终,我们几乎看不到没有 Prometheus 运行的 Kubernetes 集群。

Prometheus 社区的强大专注也促使其他开源项目得以发展,以将 Prometheus 的部署模型扩展到单个节点之外(例如 Cortex Thanos  等)。更不用说云厂商采用了 Prometheus 的 API 和数据模型(例如 Amazon Managed Prometheus Google Cloud Managed Prometheus Grafana Cloud  等)。如果您想知道 Prometheus 项目如此成功的原因,那就是:**将监控社区聚焦于重要事务**。

在这篇(篇幅很长的)博客文章中,我想介绍一种运行 Prometheus 的新操作模式,称为“Agent”。它直接内置于 Prometheus 二进制文件中。Agent 模式会禁用 Prometheus 的一些常规功能,并优化二进制文件以进行抓取和向远程位置写入。引入一种减少功能数量的模式可以实现新的使用模式。在这篇博客文章中,我将解释为什么它对 CNCF 生态系统中的某些部署是颠覆性的。我对此感到非常兴奋!

指标转发用例的历史

Prometheus 的核心设计在其整个生命周期中都没有改变。它受到 Google 的 Borgmon 监控系统  的启发,您可以将 Prometheus 服务器部署在您要监控的应用程序旁边,告诉 Prometheus 如何访问它们,并允许以固定的间隔抓取其指标的当前值。这种收集方法通常被称为“拉取模型”,是 允许 Prometheus 轻量且可靠 的核心原则。此外,它使得应用程序仪器和导出器变得极其简单,因为它们只需要提供一个简单的、人类可读的 HTTP 端点,其中包含所有跟踪指标的当前值(以 OpenMetrics 格式)。所有这些都无需复杂的推送基础设施和非琐碎的客户端库。总而言之,一个简化的典型 Prometheus 监控部署如下所示:

Prometheus high-level view

这效果很好,多年来我们已经看到了数百万个类似的成功部署,处理了数千万个活动系列。其中一些需要更长时间的保留,例如两年左右。所有这些都允许查询、告警和记录对集群管理员和开发人员都有用的指标。

然而,云原生世界在不断增长和发展。随着托管 Kubernetes 解决方案的增长以及在几秒钟内按需创建的集群,我们现在终于能够将集群视为“牛”,而不是“宠物”(换句话说,我们不太关心它们的单个实例)。在某些情况下,解决方案甚至不再有集群的概念,例如 kcp Fargate  和其他平台。

Yoda

另一个新兴的有趣用例是“**边缘**”集群或网络的出现。随着电信、汽车和物联网设备等行业采用云原生技术,我们看到越来越多非常小的集群,资源受限。这迫使所有数据(包括可观测性数据)被传输到更大、更远程的对应物,因为在这些远程节点上几乎无法存储任何东西。

这意味着什么?这意味着监控数据必须以某种方式聚合,呈现给用户,有时甚至存储在**全局**级别。这通常被称为**全局视图**功能。

直观地说,我们可以通过将 Prometheus 部署在全局级别并跨远程网络抓取指标,或者直接将指标从应用程序推送到中央位置进行监控来实现这一点。让我解释一下为什么这通常是**非常**糟糕的主意。

🔥 跨网络边界抓取可能会带来挑战,因为它会为监控管道引入新的未知因素。本地拉取模型允许 Prometheus 确切地知道指标目标为何存在问题以及何时出现问题。也许它宕机了、配置错误、重启了、响应指标太慢(例如 CPU 过载)、无法被服务发现发现、我们没有访问凭证,或者只是 DNS、网络或整个集群宕机了。将我们的抓取器置于网络之外,我们冒着通过引入与单个目标无关的不可靠性而丢失部分信息的风险。最重要的是,如果网络暂时中断,我们可能会完全失去重要的可见性。请不要这样做。不值得。(

🔥 直接从应用程序将指标推送到某个中心位置同样糟糕。特别是当您监控大量集群时,如果您看不到远程应用程序的指标,您将一无所知。应用程序是否宕机?我的接收管道是否宕机?也许应用程序的授权失败?也许它未能获取到我们远程集群的 IP 地址?也许它太慢了?也许网络中断了?更糟糕的是,您甚至可能不知道某些应用程序目标的数据丢失了。而且您也没有获得太多收益,因为您需要跟踪所有应该发送数据的实体的状态。这种设计需要仔细分析,因为它可能很容易导致失败。

注意无服务器函数和短暂的容器通常是我们考虑从应用程序进行推送以进行挽救的情况。但此时,我们谈论的是事件或我们可能想要聚合到更长生命周期时间序列的数据片段。这个主题在此处进行讨论 此处 ,欢迎您贡献并帮助我们更好地支持这些情况!

Prometheus 引入了三种方式来支持全局视图场景,每种方式都有其优缺点。让我们简要回顾一下。它们在下面的图表中以橙色显示。

Prometheus global view

  • **联邦(Federation)** 作为第一个聚合功能被引入。它允许一个全局级别的 Prometheus 服务器抓取一个叶子 Prometheus 的一部分指标。这种“联邦”抓取可以减少跨网络的一些未知因素,因为联邦端点暴露的指标包含原始样本的时间戳。然而,它通常难以联邦所有指标,并且在较长的网络分区(分钟)期间会丢失数据。
  • **Prometheus Remote Read** 允许在不进行直接 PromQL 查询的情况下,从远程 Prometheus 服务器的数据库中选择原始指标。您可以在全局级别部署 Prometheus 或其他解决方案(例如 Thanos)来对这些数据执行 PromQL 查询,同时从多个远程位置获取所需指标。这非常强大,因为它允许您“本地”存储数据,并且仅在需要时访问它。不幸的是,也有缺点。如果没有诸如 Query Pushdown  之类的功能,在极端情况下,我们会拉取数 GB 的压缩指标数据来回答单个查询。另外,如果发生网络分区,我们会暂时变得盲目。最后但同样重要的是,某些安全指南不允许入站流量,只允许出站流量。
  • 最后,我们有了 **Prometheus Remote Write**,它似乎是如今最受欢迎的选择。由于 Agent 模式专注于 Remote Write 用例,让我们详细解释一下。

远程写入 (Remote Write)

Prometheus Remote Write 协议允许我们将 Prometheus 收集到的部分或全部指标转发(流式传输)到远程位置。您可以配置 Prometheus 将某些指标(如果您愿意,包含所有元数据和示例!)转发到一个或多个支持 Remote Write API 的位置。事实上,Prometheus 同时支持摄取和发送 Remote Write,因此您可以在全局级别部署 Prometheus 来接收该流并跨集群聚合数据。

虽然官方的 Prometheus Remote Write API 规范正在审查阶段 ,但生态系统已将 Remote Write 协议采纳为默认的指标导出协议。例如,Cortex、Thanos、OpenTelemetry 以及 Amazon、Google、Grafana、Logz.io 等云服务都支持通过 Remote Write 摄取数据。

Prometheus 项目还为其 API 提供官方的合规性测试,例如针对提供 Remote Write 客户端功能的解决方案的 remote-write sender 合规性 。这是一个快速判断您是否正确实现该协议的绝佳方式。

从这样的抓取器流式传输数据可以通过允许您将指标数据存储在集中位置来启用全局视图用例。这还实现了关注点分离,这在应用程序由不同于可观测性或监控管道的团队管理时非常有用。此外,这也是 Remote Write 被供应商选择以尽可能减轻客户工作的原因。

等等,Bartek。你之前说过直接从应用程序推送指标不是最好的主意!

当然,但奇妙之处在于,即使使用 Remote Write,Prometheus 仍然使用拉取模型从应用程序收集指标,这让我们能够理解那些不同的故障模式。之后,我们对样本和系列进行批处理,然后导出、复制(推送)数据到 Remote Write 端点,从而限制了中央节点会遇到的监控未知因素的数量!

需要注意的是,可靠高效的 Remote Write 实现是一个非琐碎的问题。Prometheus 社区花了大约三年时间才提出了一个稳定且可扩展的实现。我们对 WAL(写前日志)进行了几次重写,增加了内部队列、分片、智能回退等等。所有这些都对用户隐藏了,用户可以享受高性能的流式传输或大量集中存储的数据。

动手实践 Remote Write 示例:Katacoda 教程

Prometheus 中所有这些都不是新鲜事。我们中的许多人已经在使用 Prometheus 抓取所有必需的指标,并将部分或全部指标远程写入远程位置。

如果您想尝试远程写入功能的实践体验。在这种情况下,我们推荐 Thanos Katacoda 教程,演示如何从 Prometheus 远程写入指标 ,它解释了 Prometheus 将所有指标转发到远程位置所需的所有步骤。它是**免费**的,只需注册一个帐户即可享受教程!🤗

请注意,此示例使用 Thanos 的接收模式作为远程存储。如今,您可以使用许多其他兼容 Remote Write API 的项目。

那么,如果 Remote Write 工作正常,为什么我们还要为 Prometheus 添加特殊的 Agent 模式呢?

Prometheus Agent 模式

从 Prometheus v2.32.0(下一个版本)开始,任何人都可以使用实验性的 --enable-feature=agent 标志来运行 Prometheus 二进制文件。如果您想在发布前尝试,请随时使用 Prometheus v2.32.0-beta.0  或使用我们的 quay.io/prometheus/prometheus:v2.32.0-beta.0 镜像。

Agent 模式针对 Remote Write 用例优化了 Prometheus。它禁用了查询、告警和本地存储,并用自定义的 TSDB WAL 取代。其他一切保持不变:抓取逻辑、服务发现和相关配置。如果您只想将数据转发到远程 Prometheus 服务器或任何其他兼容 Remote Write 的项目,它可以作为 Prometheus 的直接替代品。本质上,它看起来像这样:

Prometheus agent

Prometheus Agent 最棒的地方在于它内置于 Prometheus 中。相同的抓取 API、相同的语义、相同的配置和发现机制。

如果您计划不进行本地查询或告警,而是将指标流式传输到外部,使用 Agent 模式有什么好处?有几点:

首先是效率。我们自定义的 Agent TSDB WAL 在成功写入后会立即删除数据。如果无法连接到远程端点,它会将数据暂时持久化到磁盘,直到远程端点恢复联机。目前这仅限于两小时的缓冲区,与非 Agent Prometheus 类似,有望很快解决 。这意味着我们不需要在内存中构建数据块。我们不需要维护完整的索引以供查询。本质上,Agent 模式使用的资源是正常 Prometheus 服务器在类似情况下使用资源的一小部分。

这种效率重要吗?是的!正如我们所提到的,在某些部署中,边缘集群上的每一 GB 内存和每一个 CPU 核心都很重要。另一方面,如今使用指标进行监控的范式已经相当成熟。这意味着以相同的成本发送更多具有更高基数的相关指标会更好。

注意随着 Agent 模式的引入,原始 Prometheus 服务器模式仍然是推荐的、稳定且得到维护的模式。带有远程存储的 Agent 模式会带来额外的复杂性。请谨慎使用。

其次,新的 Agent 模式的优势在于它能够实现更轻松的水平扩展以进行摄取。这是我最兴奋的一点。让我解释一下原因。

梦想:自动扩展指标摄取

真正的自动扩展抓取解决方案需要基于指标目标的数量以及它们暴露的指标数量。我们抓取的数据越多,我们就自动部署越多的 Prometheus 实例。如果目标数量或其指标数量减少,我们可以缩小规模并删除一些实例。这将消除手动调整 Prometheus 大小的负担,并消除在集群暂时较小时过度分配 Prometheus 的需求。

仅使用服务器模式的 Prometheus,要实现这一点很困难。这是因为服务器模式的 Prometheus 是有状态的。收集到的内容会原封不动地保留在一个地方。这意味着缩小规模的过程需要在终止之前将收集到的数据备份到现有实例。然后,我们将面临抓取重叠、误导性的陈旧标记等问题。

除此之外,我们还需要一个全局视图查询,能够聚合所有实例的所有样本(例如 Thanos Query 或 Promxy)。最后但同样重要的是,Prometheus 在服务器模式下的资源使用情况比仅仅摄取数据需要考虑的因素更多。它还包括告警、记录、查询、压缩、远程写入等,这些可能需要比指标目标数量更多的或更少的资源。

Agent 模式本质上是将发现、抓取和远程写入移到一个单独的微服务中。这使得有一个只关注摄取的专用操作模式。因此,Agent 模式下的 Prometheus 或多或少是无状态的。是的,为了避免指标丢失,我们需要部署一对高可用(HA)的 Agent 并附加持久磁盘。但从技术上讲,如果我们有成千上万个指标目标(例如容器),我们可以部署多个 Prometheus Agent,并安全地更改哪个副本正在抓取哪个目标。这是因为,最终,所有样本都将被推送到同一个中央存储。

总而言之,Agent 模式下的 Prometheus 能够轻松实现基于 Prometheus 的抓取的水平自动伸缩能力,从而应对指标目标的动态变化。这绝对是我们未来会与 Prometheus Kubernetes Operator  社区一起研究的方向。

现在让我们看看 Prometheus 中 Agent 模式的当前实现状态。它准备好使用了吗?

Agent 模式已在大规模场景下得到验证

Prometheus 的下一个版本将包含 Agent 模式作为实验性功能。标志、API 和磁盘上的 WAL 格式可能会发生变化。但由于 Grafana Labs  的开源工作,该实现的性能已经过实战检验。

我们 Agent 的自定义 WAL 的初始实现受到当前 Prometheus 服务器 TSDB WAL 的启发,并由 Robert Fratto  于 2019 年在 Prometheus 维护者 Tom Wilkie  的指导下创建的。之后,它被用于一个开源的 Grafana Agent  项目,该项目此后被许多 Grafana Cloud 客户和社区成员使用。鉴于该解决方案的成熟度,是时候将其实现捐赠给 Prometheus 以实现原生集成和更广泛的采用。Robert(Grafana Labs)在 Srikrishna(Red Hat)和社区的帮助下,将代码移植到 Prometheus 代码库,并于两周前合并到 `main` 分支!

捐赠过程非常顺利。由于一些 Prometheus 维护者之前在 Grafana Agent 中贡献过该代码,并且新的 WAL 是受 Prometheus 自己 WAL 的启发,因此现有的 Prometheus TSDB 维护者很容易就将其全面接管了!Robert 加入 Prometheus 团队担任 TSDB 维护者(恭喜!)也非常有帮助。

现在,让我们解释一下如何使用它!(

Agent 模式详细使用方法

从现在开始,如果您显示 Prometheus 的帮助输出(`--help` 标志),您应该会看到或多或少以下内容

usage: prometheus [<flags>]

The Prometheus monitoring server

Flags:
  -h, --help                     Show context-sensitive help (also try --help-long and --help-man).
      (... other flags)
      --storage.tsdb.path="data/"
                                 Base path for metrics storage. Use with server mode only.
      --storage.agent.path="data-agent/"
                                 Base path for metrics storage. Use with agent mode only.
      (... other flags)
      --enable-feature= ...      Comma separated feature names to enable. Valid options: agent, exemplar-storage, expand-external-labels, memory-snapshot-on-shutdown, promql-at-modifier, promql-negative-offset, remote-write-receiver,
                                 extra-scrape-metrics, new-service-discovery-manager. See https://prometheus.ac.cn/docs/prometheus/latest/feature_flags/ for more details.

正如前面提到的,Agent 模式是通过功能标志启用的,请使用 `--enable-feature=agent` 标志来运行 Prometheus 的 Agent 模式。现在,其余的标志要么是服务器模式和 Agent 模式都适用,要么只适用于特定模式。您可以通过查看标志帮助字符串的最后一句来确定哪个标志适用于哪种模式。“仅在服务器模式下使用”表示它仅用于服务器模式。如果您没有看到任何此类提及,则表示该标志是共享的。

Agent 模式接受相同的抓取配置,具有相同的发现选项和远程写入选项。

它还公开了一个禁用了查询能力的 Web UI,但显示了构建信息、配置、目标和服务发现信息,就像正常的 Prometheus 服务器一样。

动手实践 Prometheus Agent 示例:Katacoda 教程

与 Prometheus 远程写入教程类似,如果您想亲身体验 Prometheus Agent 的功能,我们推荐 Prometheus Agent 的 Thanos Katacoda 教程 ,该教程解释了运行 Prometheus Agent 的便捷性。

总结

希望您觉得这篇文章很有趣!在本文中,我们回顾了出现的新用例,例如

  • 边缘集群
  • 网络访问受限
  • 大量集群
  • 短暂和动态的集群

然后,我们解释了新的 Prometheus Agent 模式,该模式可以高效地将抓取的指标转发到远程写入端点。

一如既往,如果您有任何问题或反馈,请随时 在 GitHub 上提交工单或在邮件列表中提问

这篇博文是 CNCF、Grafana 和 Prometheus 之间协调发布的一部分。也请阅读 CNCF 的公告  以及关于 支撑 Prometheus Agent 的 Grafana Agent  的观点。