Bartek Płotka 自 2019 年起担任 Prometheus 维护者,同时也是 Red Hat 的首席软件工程师。CNCF Thanos 项目的合著者。CNCF 大使和 CNCF TAG 可观测性技术负责人。在他的业余时间,他与 O'Reilly 共同撰写了一本名为“高效 Go”的书。观点仅代表个人!
我个人喜欢 Prometheus 项目的地方,也是我加入团队的众多原因之一,就是该项目对目标的专注。Prometheus 一直致力于在提供实用、可靠、廉价且宝贵的基于指标的监控方面突破界限。Prometheus 超级稳定和强大的 API、查询语言和集成协议(例如远程写入和 OpenMetrics)使云原生计算基金会 (CNCF) 指标生态系统能够在这些坚实的基础上不断发展。结果是惊人的
- 我们可以看到用于获取几乎所有内容的指标的社区导出器,例如 容器、eBPF、Minecraft 服务器统计信息,甚至 园艺时植物的健康状况。
- 如今,大多数人期望云原生软件具有 HTTP/HTTPS
/metrics
端点,以便 Prometheus 可以抓取。这是 Google 内部秘密开发并在全球范围内由 Prometheus 项目开创的概念。
- 可观测性范式发生了转变。我们看到 SRE 和开发人员从一开始就严重依赖指标,这提高了软件的弹性、可调试性和数据驱动决策!
最终,我们几乎看不到没有运行 Prometheus 的 Kubernetes 集群。
Prometheus 社区的强烈关注也使其他开源项目得以发展,以将 Prometheus 部署模型扩展到单个节点之外(例如 Cortex、Thanos 等)。更不用说云供应商采用 Prometheus 的 API 和数据模型(例如 Amazon Managed Prometheus、Google Cloud Managed Prometheus、Grafana Cloud 等)。如果您想找出一个 Prometheus 项目如此成功的原因,那就是:专注于监控社区关注的事情。
在这篇(冗长)博文中,我想要介绍一种新的运行 Prometheus 的操作模式,称为“代理”。它直接内置到 Prometheus 二进制文件中。代理模式会禁用一些 Prometheus 通常的功能,并针对抓取和远程写入到远程位置优化二进制文件。引入一种减少功能数量的模式可以实现新的使用模式。在这篇博文中,我将解释为什么它对于 CNCF 生态系统中的某些部署来说是一个改变游戏规则的模式。我对此超级兴奋!
转发用例的历史
Prometheus 的核心设计在整个项目生命周期中一直保持不变。受 Google 的 Borgmon 监控系统 的启发,您可以在想要监控的应用程序旁边部署一个 Prometheus 服务器,告诉 Prometheus 如何访问它们,并允许它定期抓取其指标的当前值。这种收集方法通常被称为“拉取模型”,是 使 Prometheus 变得轻量级且可靠 的核心原则。此外,它使应用程序检测和导出器变得非常简单,因为它们只需要提供一个简单的易于理解的 HTTP 端点,其中包含所有跟踪指标的当前值(以 OpenMetrics 格式)。所有这些都无需复杂的推送基础设施和非平凡的客户端库。总的来说,典型的简化 Prometheus 监控部署如下所示
这效果很好,多年来我们已经看到了数百万个这样的成功部署,它们处理了数千万个活动时间序列。其中一些用于更长时间的保留,例如两年左右。所有这些都允许查询、警报和记录对集群管理员和开发人员都有用的指标。
然而,云原生世界正在不断发展和演变。随着托管 Kubernetes 解决方案的增长以及按需创建的集群以秒为单位出现,我们现在终于能够将集群视为“牛群”,而不是“宠物”(换句话说,我们不再关心这些集群的单个实例)。在某些情况下,解决方案甚至不再具有集群的概念,例如 kcp、Fargate 和其他平台。
另一个有趣的用例是边缘集群或网络的概念。随着电信、汽车和物联网设备等行业采用云原生技术,我们看到越来越多的资源有限的小型集群。这迫使所有数据(包括可观察性)都必须传输到远程、更大的集群,因为几乎无法在这些远程节点上存储数据。
这意味着什么?这意味着监控数据必须以某种方式聚合,并呈现给用户,有时甚至存储在全局级别。这通常被称为全局视图功能。
我们可以简单地考虑通过在全局级别部署 Prometheus 并跨远程网络抓取指标,或者将指标直接从应用程序推送到中心位置进行监控,来实现这一点。让我解释一下为什么两者通常都是非常糟糕的方案。
🔥 跨网络边界抓取可能会成为一项挑战,因为它会在监控管道中添加新的未知因素。本地拉取模型允许 Prometheus 准确地了解指标目标出现问题的具体原因和时间。可能是目标宕机、配置错误、重启、响应速度太慢而无法提供指标(例如 CPU 饱和)、服务发现无法发现、没有访问凭据,或者只是 DNS、网络或整个集群宕机。通过将我们的抓取器置于网络外部,我们可能会由于引入与单个目标无关的抓取不可靠性而丢失部分信息。除此之外,如果网络暂时宕机,我们可能会完全失去重要的可见性。请不要这样做。它不值得。(
🔥 将指标直接从应用程序推送到某个中心位置同样糟糕。特别是当您监控一个庞大的集群时,如果您看不到来自远程应用程序的指标,您将一无所知。应用程序是否宕机?我的接收器管道是否宕机?也许应用程序授权失败?也许它获取远程集群的 IP 地址失败?也许它太慢了?也许网络宕机?更糟糕的是,您可能甚至不知道某些应用程序目标的数据是否丢失。而且您并没有真正获得太多收益,因为您需要跟踪所有应该发送数据的对象的状况和状态。这种设计需要仔细分析,因为它很容易成为失败的根源。
注意: 无服务器函数和短暂容器通常是我们将从应用程序推送到中心位置作为解决方案的情况。然而,在这种情况下,我们指的是我们可能想要聚合到生命周期更长的时间序列的事件或指标片段。此主题已在
此处进行讨论,欢迎您贡献并帮助我们更好地支持这些用例!
Prometheus 引入了三种支持全局视图用例的方法,每种方法都有其优缺点。让我们简要地介绍一下这些方法。它们在下图中以橙色显示。
-
联邦是为聚合目的而引入的第一项功能。它允许全局级别的 Prometheus 服务器从叶子 Prometheus 抓取指标子集。这种“联邦”抓取减少了跨网络的某些未知因素,因为联邦端点公开的指标包含原始样本的时间戳。然而,它通常无法联邦所有指标,并且在较长的网络分区(分钟)期间不会丢失数据。
-
Prometheus 远程读取允许从远程 Prometheus 服务器的数据库中选择原始指标,而无需直接执行 PromQL 查询。您可以在全局级别部署 Prometheus 或其他解决方案(例如 Thanos)来对这些数据执行 PromQL 查询,同时从多个远程位置获取所需的指标。这非常强大,因为它允许您“本地”存储数据,并在需要时才访问。不幸的是,它也有缺点。如果没有诸如查询下推之类的功能,在极端情况下,我们需要拉取 GB 级别的压缩指标数据来回答一个单一查询。此外,如果存在网络分区,我们就会暂时失明。最后但同样重要的是,某些安全准则不允许入站流量,只允许出站流量。
- 最后,我们有Prometheus 远程写入,它似乎是目前最受欢迎的选择。由于代理模式侧重于远程写入用例,因此让我们详细解释一下。
远程写入
Prometheus 远程写入协议允许我们将 Prometheus 收集的所有指标或部分指标转发(流式传输)到远程位置。您可以配置 Prometheus 将部分指标(如果需要,可以包含所有元数据和示例!)转发到一个或多个支持远程写入 API 的位置。事实上,Prometheus 支持同时接收和发送远程写入,因此您可以在全局级别部署 Prometheus 来接收该流并跨集群聚合数据。
虽然官方的Prometheus 远程写入 API 规范处于审查阶段,但生态系统已将远程写入协议作为默认指标导出协议。例如,Cortex、Thanos、OpenTelemetry 和 Amazon、Google、Grafana、Logz.io 等云服务都支持通过远程写入接收数据。
Prometheus 项目还为其 API 提供了官方合规性测试,例如,用于提供远程写入客户端功能的解决方案的远程写入发送器合规性。这是一种快速判断您是否正确实现该协议的绝佳方法。
从这样的抓取器流式传输数据通过允许您将指标数据存储在中心位置来实现全局视图用例。这也实现了关注点分离,这在应用程序由不同团队管理而可观察性或监控管道由其他团队管理的情况下非常有用。此外,这也是供应商选择使用远程写入的原因,他们希望尽可能地从客户那里卸载工作量。
等等,Bartek。您之前提到直接从应用程序推送指标并不是最佳方案!
没错,但最棒的是,即使使用远程写入,Prometheus 仍然使用拉取模型从应用程序收集指标,这使我们能够了解这些不同的故障模式。之后,我们将样本和序列批处理并导出,并将数据复制(推送)到远程写入端点,从而限制中心点所具有的监控未知因素的数量!
重要的是要注意,可靠且高效的远程写入实现是一个非凡的难题。Prometheus 社区花了大约三年时间才提出一个稳定且可扩展的实现。我们重新实现了 WAL(预写日志)几次,添加了内部队列、分片、智能回退等等。所有这些都对用户隐藏,用户可以享受高性能的流式传输或存储在中心位置的大量指标。
动手实践远程写入示例:Katacoda 教程
所有这些对于 Prometheus 来说都不是什么新鲜事。我们中的许多人已经使用 Prometheus 抓取所有需要的指标,并将所有或部分指标远程写入到远程位置。
假设您想尝试远程写入功能的动手实践体验。在这种情况下,我们推荐Thanos Katacoda 教程,它介绍了从 Prometheus 远程写入指标,该教程解释了 Prometheus 将所有指标转发到远程位置所需的所有步骤。它是免费的,只需注册一个帐户,就可以享受教程的乐趣!🤗
请注意,此示例使用 Thanos 的接收模式作为远程存储。现在,您可以使用许多其他与远程写入 API 兼容的项目。
那么,如果远程写入效果很好,为什么我们还要为 Prometheus 添加一个特殊的代理模式呢?
Prometheus 代理模式
从 Prometheus v2.32.0
(下一个版本)开始,每个人都可以使用实验性的 --enable-feature=agent
标志运行 Prometheus 二进制文件。如果您想在发布之前尝试它,请随意使用Prometheus v2.32.0-beta.0 或使用我们的 quay.io/prometheus/prometheus:v2.32.0-beta.0
镜像。
代理模式针对远程写入用例对 Prometheus 进行了优化。它禁用了查询、警报和本地存储,并将其替换为定制的 TSDB WAL。其他一切保持不变:抓取逻辑、服务发现和相关配置。如果您只想将数据转发到远程 Prometheus 服务器或任何其他支持远程写入的项目,可以使用它作为 Prometheus 的直接替代品。本质上,它看起来像这样
Prometheus 代理最棒的地方在于它是内置于 Prometheus 中的。相同的抓取 API、相同的语义、相同的配置和发现机制。
如果您计划不本地查询或警报数据,并流式传输外部指标,那么使用代理模式有什么好处呢?有一些好处。
首先,效率。我们定制的代理 TSDB WAL 在成功写入后立即删除数据。如果它无法到达远程端点,它会将数据暂时持久存储到磁盘上,直到远程端点恢复在线。目前,这仅限于两小时缓冲区,类似于非代理 Prometheus,希望很快就能解除限制。这意味着我们不需要在内存中构建数据块。我们不需要维护一个完整的索引以进行查询。本质上,代理模式使用的是正常 Prometheus 服务器在类似情况下使用的资源的一小部分。
这种效率重要吗?当然!正如我们提到的,对于某些部署来说,边缘集群上的每 GB 内存和每个 CPU 内核都很重要。另一方面,使用指标进行监控的范式在如今已经相当成熟了。这意味着,对于相同的成本,您能够发送的具有更多基数的相关指标越多越好。
注意: 随着代理模式的引入,原始的 Prometheus 服务器模式仍然是推荐的、稳定且维护的模式。使用远程存储的代理模式会带来额外的复杂性。请谨慎使用。
其次,新代理模式的优势在于它使摄取的横向扩展变得更加容易。这是我最激动的一点。让我解释一下为什么。
梦想:可自动扩展的指标摄取
一个真正可自动扩展的抓取解决方案需要基于指标目标的数量和它们公开的指标数量。我们抓取的数据越多,我们就自动部署的 Prometheus 实例越多。如果目标数量或其指标数量下降,我们可以缩减规模并删除一些实例。这将消除手动调整 Prometheus 大小和停止在集群暂时较小时过度分配 Prometheus 的需要。
仅使用服务器模式下的 Prometheus,这很难实现。这是因为服务器模式下的 Prometheus 是有状态的。收集到的任何内容都会原样保留在一个地方。这意味着缩减规模过程需要在终止之前将收集到的数据备份到现有实例。然后,我们会遇到重叠抓取、误导性的陈旧标记等等问题。
除此之外,我们还需要一些能够跨所有实例聚合所有样本的全局视图查询(例如 Thanos Query 或 Promxy)。最后但同样重要的是,服务器模式下的 Prometheus 的资源使用情况取决于比摄取更多的因素。还有警报、记录、查询、压缩、远程写入等等,它们可能需要更多或更少的资源,而与指标目标的数量无关。
代理模式本质上将发现、抓取和远程写入迁移到一个独立的微服务。这允许专注于摄取的集中运营模型。因此,代理模式下的 Prometheus 基本上是无状态的。是的,为了避免指标丢失,我们需要部署一对高可用性的代理并为它们附加一个持久磁盘。但从技术角度来说,如果我们有数千个指标目标(例如容器),我们可以部署多个 Prometheus 代理,并安全地更改哪个副本正在抓取哪些目标。这是因为,最终,所有样本都将被推送到同一个中央存储。
总的来说,代理模式下的 Prometheus 使基于 Prometheus 的抓取能够轻松实现水平自动扩展功能,从而能够应对指标目标的动态变化。这绝对是我们将来会与 Prometheus Kubernetes 运营商 社区一起关注的内容。
现在让我们看看 Prometheus 中当前实现的代理模式状态。它可以使用了吗?
代理模式已在规模上得到验证
Prometheus 的下一个版本将包含代理模式作为实验性功能。磁盘上的标志、API 和 WAL 格式可能会发生变化。但由于 Grafana Labs' 的开源工作,该实现的性能已经过实战检验。
我们代理的自定义 WAL 的初始实现受当前 Prometheus 服务器的 TSDB WAL 启发,由 Robert Fratto 在 2019 年创建,在 Prometheus 维护者 Tom Wilkie 的指导下。它随后被用于一个开源的 Grafana Agent 项目,该项目此后已被许多 Grafana Cloud 客户和社区成员使用。鉴于该解决方案的成熟度,现在是时候将该实现捐赠给 Prometheus 以实现原生集成和更广泛的采用。Robert(Grafana Labs)在 Srikrishna(Red Hat)和社区的帮助下,将代码移植到 Prometheus 代码库,该代码库在 2 周前合并到 main
分支!
捐赠过程非常顺利。由于一些 Prometheus 维护者之前曾在 Grafana Agent 中贡献过此代码,并且由于新的 WAL 受 Prometheus 自身 WAL 的启发,因此当前的 Prometheus TSDB 维护者很容易将它完全维护!Robert 将加入 Prometheus 团队担任 TSDB 维护者(恭喜!),这也确实很有帮助。
现在,让我们解释一下如何使用它!(
如何详细使用代理模式
从现在开始,如果您显示 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.
由于代理模式位于功能标志之后,如前所述,请使用 --enable-feature=agent
标志以代理模式运行 Prometheus。现在,其余的标志要么适用于服务器和代理,要么只适用于特定模式。您可以通过查看标志帮助字符串的最后一句来查看哪个标志对应于哪个模式。“仅与服务器模式一起使用”表示它仅适用于服务器模式。如果您没有看到类似的描述,则表示该标志是共享的。
代理模式接受具有相同发现选项和远程写入选项的相同抓取配置。
它还公开了一个 Web UI,该 UI 禁用了查询功能,但显示了构建信息、配置、目标和服务发现信息,就像在正常的 Prometheus 服务器中一样。
实践 Prometheus 代理示例:Katacoda 教程
与 Prometheus 远程写入教程类似,如果您想尝试 Prometheus 代理功能的实践体验,我们建议您使用 Thanos Katacoda 的 Prometheus 代理教程,它解释了运行 Prometheus 代理是多么容易。
总结
希望您发现这很有趣!在这篇文章中,我们介绍了以下新情况:
- 边缘集群
- 访问受限的网络
- 大量的集群
- 短暂的和动态的集群
然后,我们解释了新的 Prometheus 代理模式,它允许将抓取的指标有效地转发到远程写入端点。
与往常一样,如果您有任何问题或反馈,请随时 在 GitHub 上提交问题或在邮件列表中提问。
这篇博文是 CNCF、Grafana 和 Prometheus 之间协调发布的一部分。请随时阅读 CNCF 公告 和有关 构成 Prometheus 代理基础的 Grafana 代理 的观点。