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

Bartek Płotka 自 2019 年起担任 Prometheus Maintainer,并任职于 Red Hat 担任首席软件工程师。他是 CNCF Thanos 项目的合著者,CNCF Ambassador 和 CNCF TAG Observability 的技术负责人。业余时间,他正与 O'Reilly 合作撰写一本名为《高效 Go》的书。文中的观点为作者个人观点!

我个人喜爱 Prometheus 项目的原因有很多,其中之一就是它对项目目标的专注。Prometheus 始终致力于在提供实用、可靠、经济但极具价值的基于指标的监控方面突破界限。Prometheus 超稳定且健壮的 API、查询语言和集成协议(例如 Remote Write 和 OpenMetrics)使得云原生计算基金会 (CNCF) 指标生态系统能够建立在这些坚实的基础之上。因此,许多令人惊喜的事情随之发生。

  • 我们可以看到社区提供了各种各样的 Exporter,几乎可以获取所有方面的指标,例如容器eBPFMinecraft 服务器统计数据,甚至包括园艺时植物的健康状况
  • 如今,大多数人都期望云原生软件提供一个 HTTP/HTTPS /metrics 端点,以便 Prometheus 可以抓取。这个概念最初在 Google 内部秘密开发,并由 Prometheus 项目在全球范围推广。
  • 可观测性范式发生了转变。我们看到 SRE 和开发人员从项目伊始就高度依赖指标,这提高了软件的弹性、可调试性以及数据驱动的决策能力!

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

Prometheus 社区的强大专注使得其他开源项目也得到了发展,从而将 Prometheus 的部署模型扩展到单节点之外(例如 CortexThanos 等)。更不用说云厂商也采用了 Prometheus 的 API 和数据模型(例如 Amazon Managed PrometheusGoogle Cloud Managed PrometheusGrafana Cloud 等)。如果你想找一个 Prometheus 项目如此成功的原因,那就是这个:让监控社区关注真正重要的东西

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

转发用例的历史

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

Prometheus high-level view

这种方式运行良好,多年来我们已经看到了数百万成功的部署,它们处理着数千万的活跃时间序列。其中一些用于更长的数据保留,例如两年左右。所有这些都支持查询、告警和记录对集群管理员和开发人员都有用的指标。

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

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,这似乎是目前最流行的选择。

Remote Write

Prometheus Remote Write 协议允许我们将 Prometheus 收集的所有或部分指标转发(流式传输)到远程位置。你可以配置 Prometheus 将一些指标(如果你需要,可以包括所有元数据和 Exemplar!)转发到一个或多个支持 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 发送端合规性测试。这是一个快速判断你是否正确实现了该协议的绝佳方式。

从这样的抓取器流式传输数据,通过将指标数据存储在中心位置,从而实现全局视图的用例。这也实现了关注点分离,这对于应用程序由与可观测性或监控流水线不同的团队管理的情况非常有用。此外,这也是为什么希望尽可能为客户分担工作的供应商选择 Remote Write 的原因。

等一下,Bartek。你刚才不是说过直接从应用程序推送指标不是最好的主意吗!

当然,但令人惊叹的部分是,即使使用 Remote Write,Prometheus 仍然使用拉取模型从应用程序收集指标,这使我们能够了解不同的故障模式。之后,我们将样本和时间序列进行批量处理,并导出、复制(推送)数据到 Remote Write 端点,从而限制中心点监控的未知因素数量!

需要注意的是,实现可靠且高效的远程写入并非易事。Prometheus 社区花费了大约三年时间才开发出稳定且可扩展的实现。我们多次重新实现了 WAL(写前日志),增加了内部队列、分片、智能回退等等。所有这些都对用户隐藏,用户可以享受高性能的流式传输或将大量指标存储在中心位置。

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

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

假设你想亲身体验远程写入功能。在这种情况下,我们推荐 Thanos Katacoda 关于从 Prometheus 远程写入指标的教程,该教程解释了 Prometheus 将所有指标转发到远程位置所需的所有步骤。它是免费的,只需注册一个账号即可享受教程! 🤗

请注意,本例使用接收模式下的 Thanos 作为远程存储。如今,你可以使用许多其他与 remote write API 兼容的项目。

那么,如果远程写入运行良好,为什么我们还要在 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 模式的好处是它使得摄取(ingestion)更容易进行水平扩展。这是我最兴奋的一点。让我解释一下原因。

梦想:自动扩展的指标摄取

一个真正的自动抓取扩展解决方案需要基于指标目标的数量以及它们暴露的指标数量。需要抓取的数据越多,我们就会自动部署更多的 Prometheus 实例。如果目标的数量或指标数量下降,我们可以缩减并移除一些实例。这将减轻手动调整 Prometheus 大小的负担,并避免在集群暂时很小的情况下过度分配 Prometheus 资源。

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

除此之外,我们还需要一些全局视图查询,能够聚合所有实例的所有样本(例如 Thanos Query 或 Promxy)。最后但同样重要的是,服务器模式下 Prometheus 的资源使用不仅取决于摄取。还有告警、记录规则、查询、压缩、远程写入等功能,它们所需的资源可能与指标目标的数量无关。

Agent 模式本质上将服务发现、抓取和远程写入移动到单独的微服务中。这使得操作模型能够专注于摄取。因此,Agent 模式下的 Prometheus 或多或少是无状态的。是的,为了避免指标丢失,我们需要部署一对高可用 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 Maintainer Tom Wilkie 的指导下创建。之后它被用于开源项目 Grafana Agent,并被许多 Grafana Cloud 客户和社区成员使用。鉴于该解决方案的成熟度,现在是将该实现贡献给 Prometheus,以实现原生集成和更广泛的应用的时候了。Robert (Grafana Labs) 在 Srikrishna (Red Hat) 和社区的帮助下,将代码移植到 Prometheus 代码库,并于两周前合并到 main 分支!

捐赠过程相当顺利。由于一些 Prometheus Maintainer 之前在 Grafana Agent 中为此代码贡献过,并且新的 WAL 受 Prometheus 自己的 WAL 启发,因此当前的 Prometheus TSDB Maintainer 接管其完整维护工作并不困难! Robert 加入 Prometheus 团队并成为 TSDB Maintainer(祝贺他!)也非常有帮助。

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

如何详细使用 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 标志在 Agent 模式下运行 Prometheus。现在,其余的标志要么同时适用于服务器和 Agent 模式,要么仅适用于特定模式。你可以通过检查标志帮助字符串的最后一句来判断哪个标志适用于哪种模式。“仅用于服务器模式”(Use with server mode only)表示它仅用于服务器模式。如果你没有看到类似的说明,则表示该标志是共享的。

Agent 模式接受与正常模式相同的抓取配置,包括相同的发现选项和远程写入选项。

它还暴露了一个 Web UI,虽然查询功能被禁用,但会像正常的 Prometheus 服务器一样显示构建信息、配置、目标和服务发现信息。

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

与 Prometheus 远程写入教程类似,如果你想亲身体验 Prometheus Agent 的功能,我们推荐 Thanos Katacoda 关于 Prometheus Agent 的教程,该教程解释了运行 Prometheus Agent 是多么容易。

总结

我希望你觉得这篇文章有趣!在这篇文章中,我们探讨了一些新出现的用例,例如:

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

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

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

这篇博客文章是 CNCF、Grafana 和 Prometheus 之间协调发布的一部分。也欢迎阅读 CNCF 公告以及关于 Prometheus Agent 底层 Grafana Agent 的文章