拉取无法扩展 - 还是可以扩展?

我们来谈谈一个特别持久的误解。每当讨论到监控系统和 Prometheus 的基于拉取的指标收集方法时,总会有人插话说基于拉取的方法“从根本上无法扩展”。给出的理由通常很模糊,或者只适用于与 Prometheus 根本不同的系统。事实上,我们在最大规模的情况下使用过基于拉取的监控,这一说法与我们自己的运营经验相悖。

我们已经有一个关于 为什么 Prometheus 选择拉取而不是推送 的常见问题解答条目,但它没有特别关注扩展方面。让我们仔细看看围绕这一说法的常见误解,并分析它们是否以及如何适用于 Prometheus。

Prometheus 不是 Nagios

当人们想到主动拉取的监控系统时,他们通常会想到 Nagios。Nagios 以扩展性不佳而闻名,部分原因是它为主动检查生成子进程,这些子进程可以在 Nagios 主机上运行任意操作,以确定特定主机或服务的健康状况。这种检查架构确实无法很好地扩展,因为中央 Nagios 主机很快就会不堪重负。因此,人们通常将检查配置为每隔几分钟才执行一次,或者他们会遇到更严重的问题。

然而,Prometheus 采取的方法从根本上有所不同。它不是执行检查脚本,而是仅通过网络从一组已检测的目标收集时间序列数据。对于每个目标,Prometheus 服务器只是通过 HTTP(以高度并行的方式,使用 goroutine)获取该目标所有指标的当前状态,并且没有其他与拉取相关的执行开销。这引出了下一个要点

谁发起连接并不重要

出于扩展目的,谁发起 TCP 连接来传输指标并不重要。无论你采用哪种方式,建立连接的工作量都比指标负载和其他所需工作量小。

但是基于推送的方法可以使用 UDP 并完全避免建立连接,你说得对!没错,但与 Prometheus 服务器为摄取数据(尤其是将时间序列数据持久化到磁盘)所做的其他工作相比,Prometheus 中的 TCP/HTTP 开销仍然可以忽略不计。为了用数字来说明这一点:一台大型 Prometheus 服务器可以轻松存储数百万个时间序列,每秒记录 800,000 个传入样本(根据 SoundCloud 的真实生产指标数据测量)。给定 10 秒的抓取间隔和每台主机 700 个时间序列,这允许你从单个 Prometheus 服务器监控超过 10,000 台机器。这里的扩展瓶颈从来都与拉取指标无关,而通常与 Prometheus 服务器将数据摄取到内存中,然后可持续地将数据持久化和过期到磁盘/SSD 的速度有关。

此外,尽管现在的网络非常可靠,但使用基于 TCP 的拉取方法可以确保指标数据可靠到达,或者监控系统至少可以立即知道何时由于网络中断而导致指标传输失败。

Prometheus 不是基于事件的系统

一些监控系统是基于事件的。也就是说,它们会立即将每个单独的事件(HTTP 请求、异常,等等)报告给中央监控系统。然后,这个中央系统要么将事件聚合为指标(StatsD 是这方面的主要示例),要么单独存储事件以供稍后处理(ELK 堆栈就是这方面的一个示例)。在这样的系统中,拉取确实会成为问题:被检测的服务必须在拉取之间缓冲事件,并且拉取必须非常频繁地发生,以便模拟基于推送的方法的相同“活跃性”,并且不会使事件缓冲区不堪重负。

然而,再次强调,Prometheus 不是基于事件的监控系统。你不会向 Prometheus 发送原始事件,它也不能存储它们。Prometheus 的业务是收集聚合的时间序列数据。这意味着它只对定期收集给定指标集的当前状态感兴趣,而不是导致生成这些指标的底层事件。例如,一个被检测的服务不会在处理每个 HTTP 请求时向 Prometheus 发送消息,而只是在内存中增加这些请求的计数。这每秒可能发生数十万次,而不会产生任何监控流量。然后,Prometheus 只是每 15 或 30 秒(或你配置的任何时间)向服务实例询问当前的计数器值,并将该值与抓取时间戳一起存储为样本。其他指标类型,如仪表盘、直方图和摘要,也以类似的方式处理。由此产生的监控流量很低,在这种情况下,基于拉取的方法也不会造成问题。

但是现在我的监控需要知道我的服务实例!

使用基于拉取的方法,你的监控系统需要知道哪些服务实例存在以及如何连接到它们。有些人担心这需要在监控系统方面进行额外的配置,并将此视为运营可扩展性问题。

我们会认为,在任何情况下,对于认真的监控设置,你都无法逃避这种配置工作:如果你的监控系统不知道世界应该是什么样子,以及应该存在哪些被监控的服务实例,那么它如何能够判断一个实例只是从未报告,是由于中断而宕机,还是真的不再打算存在?只有当您从不关心单个实例的健康状况时,这才是可以接受的,就像当您只运行临时工作程序时,只要有足够数量的工作程序报告一些结果就足够了。大多数环境并非完全如此。

如果监控系统无论如何都需要知道世界的期望状态,那么基于推送的方法实际上需要更多的配置。不仅你的监控系统需要知道应该存在哪些服务实例,而且你的服务实例现在也需要知道如何访问你的监控系统。基于拉取的方法不仅需要更少的配置,而且还使你的监控设置更加灵活。使用拉取,你可以在笔记本电脑上运行生产监控的副本,以便进行实验。它还允许你使用其他工具获取指标或手动检查指标端点。为了获得高可用性,拉取允许你并行运行两个配置相同的 Prometheus 服务器。最后,如果你必须移动你的监控可访问的端点,基于拉取的方法不需要你重新配置所有指标源。

在实践方面,Prometheus 通过其内置的对云提供商和容器调度系统的各种服务发现机制的支持,可以轻松配置世界的期望状态:Consul、Marathon、Kubernetes、EC2、基于 DNS 的 SD、Azure、Zookeeper Serversets 等等。如果需要,Prometheus 还允许你插入自己的自定义机制。在微服务世界或任何多层架构中,如果你的监控系统使用与你的服务实例用于发现其后端相同的方法来发现要监控的目标,从根本上来说也是一个优势。这样你就可以确保你正在监控与服务生产流量相同的目标,并且你只需要维护一个发现机制。

意外地 DDoS 你的监控

无论你拉取还是推送,如果发送的样本超过其处理能力,任何时间序列数据库都会崩溃。然而,根据我们的经验,基于推送的方法稍微更容易意外地使你的监控瘫痪。如果对从哪些实例摄取哪些指标的控制不是集中的(在你的监控系统中),那么你就会面临实验性或恶意作业突然向你的生产监控推送大量垃圾数据并使其崩溃的危险。仍然有很多方法可以使基于拉取的方法发生这种情况(它只控制从哪里拉取指标,但不控制指标负载的大小和性质),但风险较低。更重要的是,此类事件可以在中心点得到缓解。

真实世界的证明

除了 Prometheus 已经被用于监控真实世界中的非常大的设置(例如,使用它来 在 DigitalOcean 监控数百万台机器)之外,还有其他突出的例子表明基于拉取的监控已成功用于尽可能大的环境中。Prometheus 的灵感来自 Google 的 Borgmon,Borgmon 曾经(并且部分仍然)在 Google 内部用于使用基于拉取的方法监控其所有关键生产服务。我们在 Google 使用 Borgmon 遇到的任何扩展问题都不是由于其拉取方法造成的。如果基于拉取的方法可以扩展到拥有数十个数据中心和数百万台机器的全球环境,你很难说拉取无法扩展。

但是拉取还有其他问题!

确实有一些设置很难使用基于拉取的方法进行监控。一个突出的例子是,当你有许多端点分散在世界各地,由于防火墙或复杂的网络设置而无法直接访问,并且在每个网段中直接运行 Prometheus 服务器是不可行的。这不太符合 Prometheus 的构建环境,尽管通常可以找到解决方法(通过 Pushgateway 或重组你的设置)。在任何情况下,这些关于基于拉取的监控的剩余担忧通常与扩展无关,而是由于围绕打开 TCP 连接的网络操作困难造成的。

一切都好了吗?

本文解决了围绕基于拉取的监控方法的最常见的可扩展性问题。随着 Prometheus 和其他基于拉取的系统在非常大的环境中成功使用,并且拉取方面在现实中没有构成瓶颈,结果应该很清楚:“拉取无法扩展”的论点不是一个真正的担忧。我们希望未来的辩论将侧重于比这个转移注意力的东西更重要的问题。