隆重推出 Prometheus Agent 模式:一种高效的云原生指标转发方式
2021 年 11 月 16 日作者 Bartlomiej Plotka (@bwplotka)
Bartek Płotka 自 2019 年起担任 Prometheus 维护者,现为 Red Hat 首席软件工程师。CNCF Thanos 项目的合著者。CNCF 大使及 CNCF TAG Observability 技术负责人。业余时间,他与 O'Reilly 合作撰写《Efficient Go》一书。本文仅代表我个人观点!
我个人之所以热爱 Prometheus 项目,也是我加入团队的众多原因之一,就是它对项目目标的专注。Prometheus 始终致力于在提供实用、可靠、廉价且极具价值的基于指标的监控方面不断突破。Prometheus 极其稳定和强大的 API、查询语言和集成协议(例如 Remote Write 和 OpenMetrics)为云原生计算基金会(CNCF)的指标生态系统在这些坚实的基础上发展壮大提供了可能。由此催生了许多了不起的成果。
- 我们可以看到社区提供了用于获取几乎所有事物指标的 exporter,例如容器、eBPF、《我的世界》服务器统计数据,甚至还有园艺中植物的健康状况。
- 如今,大多数人都期望云原生软件拥有一个可供 Prometheus 抓取的 HTTP/HTTPS `/metrics` 端点。这个概念最初在谷歌内部秘密开发,后由 Prometheus 项目在全球推广。
- 可观测性的范式已经改变。我们看到 SRE 和开发人员从第一天起就严重依赖指标,这提高了软件的弹性、可调试性以及数据驱动的决策能力!
最终,我们几乎看不到没有运行 Prometheus 的 Kubernetes 集群。
Prometheus 社区的高度专注也促进了其他开源项目的发展,这些项目将 Prometheus 的部署模型扩展到单节点之外(例如 Cortex、Thanos 等)。更不用说云服务商也纷纷采用 Prometheus 的 API 和数据模型(例如 Amazon Managed Prometheus、Google Cloud Managed Prometheus、Grafana Cloud 等)。如果你想知道 Prometheus 项目如此成功的唯一原因,那就是:让监控社区专注于真正重要的事情。
在这篇(冗长的)博文中,我想介绍一种名为“Agent”的 Prometheus 新运行模式。它直接内置于 Prometheus 二进制文件中。Agent 模式禁用了 Prometheus 的一些常规功能,并对二进制文件进行了优化,使其专用于抓取指标并将其远程写入到其他位置。引入一个减少功能的模式,反而开启了新的使用方式。在本文中,我将解释为什么它对 CNCF 生态系统中的某些部署来说是一个颠覆性的改变。我对此感到非常兴奋!
转发用例的历史
Prometheus 的核心设计自项目诞生以来一直未变。受谷歌 Borgmon 监控系统的启发,你可以在想要监控的应用程序旁边部署一个 Prometheus 服务器,告诉 Prometheus 如何访问它们,并让它定期抓取指标的当前值。这种采集方法通常被称为“拉模型”(pull model),是使 Prometheus 轻量且可靠的核心原则。此外,它使应用程序埋点和 exporter 变得极其简单,因为它们只需要提供一个简单的人类可读的 HTTP 端点,其中包含所有被跟踪指标的当前值(以 OpenMetrics 格式)。所有这些都无需复杂的推送基础设施和繁琐的客户端库。总的来说,一个简化的典型 Prometheus 监控部署如下所示:
这种方式效果很好,多年来我们已经见证了数百万个成功的类似部署,处理着数千万个活跃的时间序列。其中一些部署需要长期保留数据,比如两年左右。所有这些都支持查询、告警和记录指标,对集群管理员和开发人员都很有用。
然而,云原生的世界在不断成长和演变。随着托管 Kubernetes 解决方案的增长以及集群可以在几秒钟内按需创建,我们现在终于能够将集群视为“牛”(cattle),而不是“宠物”(pets)(换句话说,我们不再那么关心它们的单个实例)。在某些情况下,解决方案甚至不再有集群的概念,例如 kcp、Fargate 和其他平台。
另一个有趣的用例是**边缘(Edge)**集群或网络的概念。随着电信、汽车和物联网设备等行业采用云原生技术,我们看到越来越多资源受限的小型集群。这迫使所有数据(包括可观测性数据)都必须传输到远程、更大的对应系统中,因为几乎没有任何东西可以存储在这些远程节点上。
这意味着什么?这意味着监控数据必须以某种方式在*全局*层面进行聚合、呈现给用户,有时甚至需要存储。这通常被称为**全局视图(Global-View)**功能。
简单地想,我们可以通过两种方式实现这一点:要么将 Prometheus 部署在全局层面,跨远程网络抓取指标;要么从应用程序直接将指标推送到中央位置进行监控。让我解释一下为什么这两种方法通常都是*非常*糟糕的主意。
🔥 跨网络边界抓取指标可能会成为一个挑战,因为它会在监控管道中引入新的未知因素。本地拉取模型让 Prometheus 能够确切地知道指标目标出现问题的原因和时间。也许它宕机了、配置错误、重启了、因为 CPU 饱和而响应缓慢、服务发现找不到它、我们没有访问凭证,或者只是 DNS、网络或整个集群都出了问题。如果把抓取器放在网络之外,我们就有可能因为与单个目标无关的抓取不可靠性而丢失部分信息。此外,如果网络暂时中断,我们还可能完全失去重要的可见性。请不要这样做,这不值得。(
🔥 直接从应用程序将指标推送到某个中央位置同样糟糕。特别是当你监控一个庞大的集群时,如果你看不到来自远程应用程序的指标,你几乎一无所知。是应用程序宕机了吗?是我的接收管道出问题了吗?也许是应用程序授权失败了?也许它无法获取我远程集群的 IP 地址?也许它太慢了?也许是网络中断了?更糟糕的是,你甚至可能不知道某些应用程序目标的数据丢失了。而且你也没有获得太多好处,因为你仍然需要跟踪所有应该发送数据的东西的状态和状况。这样的设计需要仔细分析,因为它太容易导致失败了。
注意无服务器函数和生命周期短暂的容器常常让我们想到从应用程序推送指标来解决问题。然而,在这种情况下,我们讨论的是事件或指标片段,我们可能希望将它们聚合成生命周期更长的时间序列。这个话题在这里有讨论,欢迎参与并帮助我们更好地支持这些场景!
Prometheus 引入了三种方式来支持全局视图用例,每种方式各有优缺点。让我们简要地回顾一下。它们在下图中以橙色显示。
- 联邦(Federation)是为聚合目的引入的第一个功能。它允许一个全局级别的 Prometheus 服务器从一个叶节点 Prometheus 抓取一部分指标。这种“联邦”抓取减少了跨网络的一些未知因素,因为联邦端点暴露的指标包含了原始样本的时间戳。然而,它通常存在无法联邦所有指标以及在较长时间(数分钟)的网络分区期间会丢失数据的问题。
- Prometheus Remote Read 允许从远程 Prometheus 服务器的数据库中选择原始指标,而无需直接进行 PromQL 查询。你可以在全局层面部署 Prometheus 或其他解决方案(如 Thanos),对这些数据执行 PromQL 查询,同时从多个远程位置获取所需的指标。这非常强大,因为它允许你将数据存储在“本地”,仅在需要时访问。不幸的是,它也有缺点。如果没有像 Query Pushdown 这样的功能,在极端情况下,我们可能需要拉取数 GB 的压缩指标数据来回答一个查询。此外,如果出现网络分区,我们将暂时失明。最后但同样重要的是,某些安全准则不允许入口流量,只允许出口流量。
- 最后,我们有 Prometheus Remote Write,这似乎是目前最受欢迎的选择。由于 Agent 模式专注于远程写入用例,让我们更详细地解释一下它。
远程写入 (Remote Write)
Prometheus Remote Write 协议允许我们将 Prometheus 收集的全部或部分指标转发(流式传输)到远程位置。你可以配置 Prometheus 将一些指标(如果需要,可以包含所有元数据和 exemplars!)转发到一个或多个支持 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 端点,从而限制了中心点监控的未知因素!
需要注意的是,一个可靠且高效的远程写入实现是一个不容小觑的难题。Prometheus 社区花了大约三年时间才打造出一个稳定且可扩展的实现。我们多次重写了 WAL(预写日志),增加了内部队列、分片、智能退避等机制。所有这些都对用户隐藏,用户可以享受到高性能的流式传输或将大量指标存储在中心位置的便利。
动手实践 Remote Write 示例:Katacoda 教程
所有这些在 Prometheus 中都不是新功能。我们中的许多人已经在使用 Prometheus 抓取所有必需的指标,并将其全部或部分远程写入到其他位置。
如果你想亲身体验远程写入功能,我们推荐 Thanos Katacoda 上的 Prometheus 远程写入指标教程,它解释了 Prometheus 将所有指标转发到远程位置所需的所有步骤。它是**免费**的,只需注册一个账户即可享受教程!🤗
请注意,此示例使用接收模式下的 Thanos 作为远程存储。如今,你可以使用许多其他与远程写入 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 模式专为远程写入用例优化了 Prometheus。它禁用了查询、告警和本地存储功能,并用一个定制的 TSDB WAL 取代了它们。其他一切保持不变:抓取逻辑、服务发现和相关配置。如果你只想将数据转发到远程 Prometheus 服务器或任何其他兼容 Remote-Write 的项目,它可以作为 Prometheus 的直接替代品。本质上,它看起来是这样的:
Prometheus Agent 最棒的地方在于它内置于 Prometheus 中。同样的抓取 API、同样的语义、同样的配置和发现机制。
如果你不打算在本地查询或告警数据,而是将指标流式传输到外部,使用 Agent 模式有什么好处呢?有以下几点:
首先是效率。我们定制的 Agent TSDB WAL 在成功写入后会立即删除数据。如果无法连接到远程端点,它会暂时将数据持久化到磁盘,直到远程端点恢复在线。目前这仅限于两小时的缓冲,与非 Agent 模式的 Prometheus 类似,希望很快能解除这个限制。这意味着我们不需要在内存中构建数据块,也不需要为查询目的维护一个完整的索引。基本上,在类似情况下,Agent 模式使用的资源只是普通 Prometheus 服务器的一小部分。
这种效率重要吗?是的!正如我们所提到的,对于某些部署,边缘集群上使用的每一个 GB 的内存和每一个 CPU 核心都很重要。另一方面,使用指标进行监控的范式如今已相当成熟。这意味着,以相同的成本能够传输更多相关、更多基数的指标,效果就越好。
注意随着 Agent 模式的引入,原始的 Prometheus server 模式仍然是推荐的、稳定且受维护的模式。Agent 模式与远程存储相结合带来了额外的复杂性,请谨慎使用。
其次,新的 Agent 模式的另一个好处是,它使得数据采集的水平扩展变得更容易。这是我最兴奋的一点。让我解释一下为什么。
梦想:自动扩展的指标采集
一个真正的自动扩展抓取解决方案需要基于指标目标的数量以及它们暴露的指标数量。我们需要抓取的数据越多,就自动部署越多的 Prometheus 实例。如果目标数量或它们的指标数量下降,我们就可以缩减并移除一些实例。这将消除手动调整 Prometheus 大小的负担,并避免在集群规模暂时较小时过度分配 Prometheus 资源。
仅使用 Prometheus server 模式,这很难实现。这是因为 server 模式下的 Prometheus 是有状态的。任何被收集的数据都会原封不动地保留在一个地方。这意味着缩减过程需要在终止前将收集到的数据备份到现有实例。然后我们还会遇到抓取重叠、误导性过时标记等问题。
除此之外,我们还需要一个能够聚合所有实例样本的全局视图查询(例如 Thanos Query 或 Promxy)。最后但同样重要的是,server 模式下 Prometheus 的资源使用量不仅仅取决于数据采集。还有告警、记录规则、查询、压缩、远程写入等,这些可能需要或多或少的资源,而与指标目标的数量无关。
Agent 模式实质上是将发现、抓取和远程写入功能转移到一个独立的微服务中。这使得运营模式可以只专注于数据采集。因此,Agent 模式下的 Prometheus 或多或少是无状态的。是的,为了避免指标丢失,我们需要部署一个 HA 对的 Agent,并为它们挂载一个持久化磁盘。但从技术上讲,如果我们有数千个指标目标(例如容器),我们可以部署多个 Prometheus Agent,并安全地更改哪个副本抓取哪些目标。这是因为,最终所有样本都将被推送到同一个中央存储。
总的来说,Prometheus 的 Agent 模式为基于 Prometheus 的抓取提供了简单的水平自动扩展能力,能够对指标目标的动态变化做出反应。这绝对是我们未来将与 Prometheus Kubernetes Operator 社区共同探索的方向。
现在,让我们来看看 Prometheus Agent 模式当前的实现状态。它是否已准备好使用?
Agent 模式已在规模化场景下得到验证
下一个 Prometheus 版本将把 Agent 模式作为一个实验性功能包含在内。标志、API 和磁盘上的 WAL 格式可能会发生变化。但 благодаря Grafana Labs 的开源工作,该实现的性能已经过实战检验。
我们 Agent 定制 WAL 的最初实现灵感来自当前 Prometheus server 的 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` 标志以 Agent 模式运行 Prometheus。现在,其余的标志要么适用于 server 和 Agent 模式,要么仅适用于特定模式。你可以通过检查标志帮助字符串的最后一句来确定哪个标志适用于哪种模式。“Use with server mode only”表示它仅适用于 server 模式。如果你没有看到这样的说明,则表示该标志是共享的。
Agent 模式接受相同的抓取配置,具有相同的发现选项和远程写入选项。
它还提供一个禁用了查询功能的 Web UI,但会像普通的 Prometheus 服务器一样显示构建信息、配置、目标和服务发现信息。
动手实践 Prometheus Agent 示例:Katacoda 教程
与 Prometheus 远程写入教程类似,如果你想亲身体验 Prometheus Agent 的功能,我们推荐 Thanos Katacoda 上的 Prometheus Agent 教程,它解释了运行 Prometheus Agent 是多么容易。
总结
希望你觉得这篇文章有趣!在本文中,我们探讨了出现的新用例,例如:
- 边缘集群
- 访问受限的网络
- 大量的集群
- 临时的和动态的集群
然后,我们解释了新的 Prometheus Agent 模式,它允许将抓取到的指标高效地转发到远程写入端点。
一如既往,如果你有任何问题或反馈,请随时在 GitHub 上提交工单或在邮件列表中提问。
这篇博文是 CNCF、Grafana 和 Prometheus 协同发布的一部分。也欢迎阅读 CNCF 的公告以及关于作为 Prometheus Agent 基础的 Grafana Agent 的看法。