拉取无法扩展——是这样吗?
2016年7月23日作者 Julius Volz
让我们来谈谈一个特别顽固的迷思。每当讨论监控系统并提及Prometheus基于拉取的指标收集方法时,总有人不可避免地插话称,基于拉取的方法“根本无法扩展”。给出的理由往往模糊不清,或者只适用于与Prometheus根本不同的系统。事实上,我们曾在最大规模的环境中使用基于拉取的监控,这一说法与我们自己的操作经验相悖。
我们已经有一个关于 Prometheus为何选择拉取而非推送 的常见问题解答条目,但它并未专门关注扩展性方面。让我们仔细看看围绕这一说法的常见误解,并分析它们是否以及如何适用于Prometheus。
Prometheus不是Nagios
当人们想到主动拉取的监控系统时,通常会想到Nagios。Nagios因其扩展性不佳而闻名,部分原因是它会为主动检查生成子进程,这些子进程可以在Nagios主机上执行任意操作,以确定特定主机或服务的健康状况。这种检查架构确实扩展性不好,因为中央Nagios主机很快就会不堪重负。因此,人们通常会配置检查每隔几分钟才执行一次,否则就会遇到更严重的问题。
然而,Prometheus采取了根本不同的方法。它不执行检查脚本,而只是通过网络从一组已检测的目标收集时间序列数据。对于每个目标,Prometheus服务器只是通过HTTP(以高度并行的方式,使用goroutines)获取该目标所有指标的当前状态,并且没有其他与拉取相关的执行开销。这引出了我们的下一点。
谁发起连接并不重要
为了扩展性,谁发起TCP连接来传输指标并不重要。无论哪种方式,建立连接的开销与指标负载及其他所需工作相比都是微不足道的。
但是你说,基于推送的方法可以使用UDP并完全避免连接建立!没错,但Prometheus中的TCP/HTTP开销与Prometheus服务器摄取数据(尤其是在磁盘上持久化时间序列数据)所需做的其他工作相比仍然可以忽略不计。举一些数字来说明:一个大型Prometheus服务器可以轻松存储数百万个时间序列,每秒记录80万个传入样本(根据SoundCloud的真实生产指标数据测量)。鉴于10秒的抓取间隔和每台主机700个时间序列,这允许您从单个Prometheus服务器监控超过10,000台机器。这里的扩展性瓶颈从未与拉取指标有关,而是通常与Prometheus服务器将数据摄取到内存中,然后可持续地将数据持久化并从磁盘/SSD中过期数据的速度有关。
此外,尽管如今网络相当可靠,但使用基于TCP的拉取方法可以确保指标数据可靠到达,或者至少让监控系统在网络故障导致指标传输失败时立即知晓。
Prometheus不是基于事件的系统
一些监控系统是基于事件的。也就是说,它们会将每个单独的事件(HTTP请求、异常,等等)在发生时立即报告给中央监控系统。然后,这个中央系统要么将事件聚合为指标(StatsD是其主要例子),要么单独存储事件以供后续处理(ELK堆栈就是其中一个例子)。在这样的系统中,拉取确实会成为问题:被检测的服务将不得不在拉取之间缓冲事件,并且拉取必须以极高的频率发生,才能模拟基于推送方法所具有的相同“实时性”,并且不会使事件缓冲区过载。
然而,Prometheus也不是一个基于事件的监控系统。您不会向Prometheus发送原始事件,Prometheus也无法存储它们。Prometheus的业务是收集聚合的时间序列数据。这意味着它只对定期收集给定指标集的当前*状态*感兴趣,而不是导致这些指标生成的底层事件。例如,一个被检测的服务在处理每个HTTP请求时不会向Prometheus发送一条消息,而只会简单地在内存中增加这些请求的计数。这可以每秒发生数十万次而不会产生任何监控流量。然后Prometheus会简单地每15或30秒(或您配置的任何时间)询问服务实例当前的计数器值,并将该值与抓取时间戳一起存储为一个样本。其他指标类型,如仪表盘(gauges)、直方图(histograms)和摘要(summaries),也以类似方式处理。由此产生的监控流量很低,在这种情况下,基于拉取的方法也不会产生问题。
但现在我的监控需要了解我的服务实例了!
对于基于拉取的方法,您的监控系统需要知道哪些服务实例存在以及如何连接到它们。一些人担心这需要监控系统进行额外的配置,并将其视为操作扩展性问题。
我们认为,在任何严肃的监控设置中,您都无法避免这种配置工作:如果您的监控系统不知道世界*应该*是什么样子,以及哪些受监控的服务实例*应该*存在,那么它怎么能判断一个实例从未报告、因中断而宕机,还是真的不再需要存在了呢?这只有在您完全不关心单个实例的健康状况时才可接受,例如当您只运行临时工作程序,并且只要有足够多的工作程序报告一些结果就足够了。大多数环境并非完全如此。
如果监控系统无论如何都需要知道世界的期望状态,那么基于推送的方法实际上总共需要*更多*的配置。您的监控系统不仅需要知道哪些服务实例应该存在,您的服务实例现在还需要知道如何到达您的监控系统。拉取方法不仅需要更少的配置,它还使您的监控设置更加灵活。使用拉取,您可以在笔记本电脑上运行生产监控的副本进行实验。它还允许您使用其他工具获取指标或手动检查指标端点。为了获得高可用性,拉取允许您并行运行两个配置相同的Prometheus服务器。最后,如果您必须移动监控可访问的端点,拉取方法不需要您重新配置所有指标源。
在实践层面,Prometheus通过其内置对各种云提供商和容器调度系统的服务发现机制的支持,使配置期望状态变得容易:Consul、Marathon、Kubernetes、EC2、基于DNS的服务发现(SD)、Azure、Zookeeper Serversets等。如果需要,Prometheus还允许您插入自己的自定义机制。在微服务世界或任何多层架构中,如果您的监控系统使用与服务实例发现其后端相同的方法来发现要监控的目标,这从根本上也是一个优势。这样您就可以确保您正在监控那些正在处理生产流量的相同目标,并且您只需要维护一种发现机制。
意外地对您的监控系统进行DDoS攻击
无论您是拉取还是推送,如果您发送的样本超过时间序列数据库所能处理的量,它都会崩溃。然而,根据我们的经验,基于推送的方法更容易意外地使您的监控系统瘫痪。如果对从哪些实例摄取哪些指标的控制不是集中化的(在您的监控系统中),那么您就会面临实验性或恶意作业突然向您的生产监控系统推送大量垃圾数据并使其瘫痪的危险。基于拉取的方法(它只控制从哪里拉取指标,而不控制指标负载的大小和性质)仍然有很多方式可能发生这种情况,但风险较低。更重要的是,此类事件可以在一个中心点进行缓解。
现实世界中的证据
除了Prometheus已经在现实世界中被用于监控非常大的设置(例如在DigitalOcean监控数百万台机器)这一事实之外,还有其他突出的例子表明基于拉取的监控在最大可能的环境中得到了成功应用。Prometheus的灵感来源于谷歌的Borgmon,Borgmon在谷歌内部曾(并且部分仍在)用于通过基于拉取的方法监控其所有关键生产服务。我们在谷歌使用Borgmon时遇到的任何扩展性问题也并非由于其拉取方法。如果基于拉取的方法能够扩展到拥有数十个数据中心和数百万台机器的全球环境,那么你很难说拉取无法扩展。
但是拉取还有其他问题!
确实有些设置难以通过基于拉取的方法进行监控。一个突出的例子是,当您有许多分布在世界各地,由于防火墙或复杂的网络设置而无法直接访问的端点,并且在每个网络段中直接运行Prometheus服务器是不可行的。这并非Prometheus设计之初所针对的环境,尽管通常可以找到变通方法(通过Pushgateway或重构您的设置)。无论如何,这些关于基于拉取监控的剩余担忧通常与扩展性无关,而是由于围绕打开TCP连接的网络操作困难所致。
那么一切都好吗?
本文解决了关于基于拉取的监控方法最常见的扩展性担忧。鉴于Prometheus及其他基于拉取的系统已在非常大的环境中成功使用,并且拉取方面在现实中并未构成瓶颈,结果应该很清楚:“拉取无法扩展”的论点并非一个真正的问题。我们希望未来的辩论将侧重于比这个障眼法更重要的方面。