本文介绍 Prometheus 使用中的一些最佳实践与思考方法,部分建议参考自《Prometheus Up & Running》一书,仅供学习。

当您考虑使用新技术时,最好开始推出一些不需要花费太多精力的小型产品,也不要过早地让您完成全面推出。在现有系统中使用Prometheus时,我建议首先运行Node exporter和Prometheus。节点导出器涵盖了可能从其他监视系统中使用的所有计算机级度量标准。在此阶段,您将获得各种各样的度量标准,只需很少的工作量,您应该熟悉Prometheus,设置一些仪表板,甚至可能做一些警报。接下来,我建议您查看您正在使用的第三方系统以及为其存在哪些导出器并开始部署这些系统。例如,如果您有网络设备,则可以运行SNMP导出器,如果您有基于JVM的应用程序(如Kafka或Cassandra),则可以使用JMX导出器,如果需要黑盒监控,则可以使用Blackbox导出器。此阶段的目标是尽可能少地尽可能多地获取系统中不同部分的指标。

到目前为止,您将对Prometheus感到满意,并且已经找到了您的方法,例如服务发现。您可以单独完成所有前面的部署步骤。下一步是开始检测组织自己的应用程序,这可能涉及要求其他人参与并投入时间进行监控。能够展示到目前为止您已经设置的所有监控和仪表板(由出口商支持)将使得使用Prometheus销售其他人更加容易,广泛地检测所有代码,因为第一步不太可能获得的买入。

和以前一样,在添加工具时,您希望从可以获得最大收益的指标开始。在应用程序中查找大量流量通过的阻塞点。例如,如果您拥有所有应用程序用于彼此通信的公共HTTP库,并且您使用基本RED度量标准对其进行检测,如“服务检测”中所述,您将获得大量的关键性能指标。只需一次仪器更换即可在线提供服务。如果您有来自其他监控系统的现有工具,则可以部署集成,例如StatsD和Graphite导出器,以利用您已有的工具。随着时间的推移,您不仅要完全转换到Prometheus仪器,还要进一步检测应用程序。随着您对Prometheus的使用越来越多,以满足越来越多的监控和指标监控需求,您应该开始关闭不再需要的其他监控系统。一家公司随着时间的推移最终会有10多个不同的监控系统并不罕见,因此在实际情况下进行整合总是有益的。

该计划是一般指导原则,您可以并且应该适应您的情况。例如,如果您是开发人员,则可以直接参与检测应用程序。您甚至可以在没有任何工具的情况下向应用程序添加客户端库,以便利用CPU使用率和垃圾收集等现成指标。

扩展Prometheus

通常,每个数据中心开始使用一个Prometheus服务器。 Prometheus旨在与其监控的网络运行在同一网络上,因为这样可以减少事情失败的方式,对齐故障域,并为Prometheus正在抓取的目标提供低延迟,高带宽的网络访问。单个Prometheus非常高效,因此您可能会使用一个Prometheus来完成整个数据中心的监控需求,这比您想象的要长。但是,在某些时候,操作开销,性能或社交考虑将导致您开始拆分Prometheus的部分以分离Prometheus服务器。例如,通常有单独的Prometheus服务器用于网络,基础设施和应用程序监控。这被称为垂直分片,它是扩展Prometheus的最佳方式。

从长远来看,您可以让每个团队都运行自己的Prometheus服务器,使他们能够选择哪些目标标签和收集间隔对他们有意义。您也可以将团队服务器作为共享服务运行,但您必须为那些对标签过于热情的团队做好准备。我看过很多次出现的模式是,开始说服团队是他们应该检测自己的代码或部署出口商的努力。但在某些时候,它会点击,他们会理解标签的力量。在很短的时间内,您可能会发现Prometheus服务器存在性能问题,因为基准的指标远远超出了在基于指标的监控系统中使用的基数。如果您将Prometheus作为共享服务运行,并且使用这些指标的团队不是那个被分页的团队,那么很难说服他们需要削减基数。但是,如果他们运行自己的Prometheus并且是在凌晨3点被唤醒的人,他们可能会更加切合实际的基于指标的监控系统以及基于日志的系统中的内容。

如果您的团队拥有特别大的系统,那么每个数据中心最终可能会有多个Prometheus服务器。基础架构团队最终可能会有一个Prometheus for Node导出器,一个用于反向代理,一个用于其他所有东西。为了便于管理,在每个Kubernetes集群中运行Prometheus服务器是正常的,而不是尝试从外部监控它们。

运行Prometheus

存储空间是您需要关注的主要资源之一。要估计您需要多少,您必须知道您将摄取多少数据。对于现有的Prometheus,您可以运行PromQL查询来报告每秒摄取的样本:

rate(prometheus_tsdb_head_samples_appended_total [5 min])

虽然Prometheus可以在生产中实现每个样本1.3个字节的压缩,但在估算时,我倾向于使用每个样本2个字节来保守。 Prometheus的默认保留期为15天,因此15天内每秒100,000个样本约为240 GB。接下来的问题是你需要多少RAM。 Prometheus 2.x中的存储工作在每两小时写出一次的块中,然后压缩到更大的时间范围内。存储引擎不进行内部缓存,而是使用内核的页面缓存。因此,您需要足够的RAM来保存块,加上开销,以及查询期间使用的RAM。 12小时的样品摄取是一个很好的起点,因此每秒100,000个样本大约为8 GB。

Prometheus在CPU上相对较轻。我的机器(具有i7-3770k CPU)的快速基准测试显示,每秒仅使用0.25个CPU来摄取100,000个样本。但这只是摄取 - 你需要额外的CPU能力来覆盖查询和录制规则。由于Go垃圾收集的CPU峰值,你应该总是至少有一个核心超过你认为你需要的核心。

网络带宽是另一个考虑因素Prometheus 2.x可以处理每秒摄取数百万个样本,这类似于许多其他类似系统的单机限制。 Prometheus通常在抓取时使用压缩,因此它使用大约20字节的网络流量来传输样本。每秒有一百万个样本,即160 Mbps的网络流量。这是千兆网卡的一大块,可能就是整个机架的全部。

这些数字只是起点。您应根据您的设置对这些进行基准测试和验证我通常建议为您的Prometheus留出空间,在资源使用方面加倍,以便在您成长时为您提供获得新硬件的时间,并且它还为您提供缓冲以应对突然的基数增加。

不要尝试使用Pushgateway来解决网络架构问题,或者更常见的是尝试将Prometheus转换为基于推送的系统。Pushgateway用于服务级批处理作业,在指标退出之前将其推送到一次。它不是为应用程序实例定期推送指标而设计的,您永远不应该将最终带有实例标签的指标推送到Pushgateway。试图以这种方式使用Pushgateway将产生瓶颈,样本的时间戳将不正确(这将导致图形工件),并且您失去了上升指标,因此很难区分进程是否故意死亡或者由于失败。 Pushgateway也没有使旧数据到期的逻辑,因为对于服务级批处理作业而言,cronjob的最后一次运行是一个月前并不会改变cronjob推送的上一个成功时间指标的有效性。

为问题进行规划

在分布式系统中,问题是生活中的事实。Prometheus没有采取尝试集群设计来处理机器故障的道路,因为这样的设计非常难以实现,并且比非预期的解决方案更不可靠。如果收集失败,Prometheus也不会尝试回填数据。如果收集失败是由于过载造成的,当负载重新下降时,回填可能只会导致再次发生过载。当监控系统具有可预测的负载并且不会加剧中断时,它会更好。由于上面的设计,如果收集失败,你的时间序列中会有一个间隙。但这不是你应该担心的事情。您不会关心绝大多数样品,包括间隙,收集后一周(如果不是更快)。对于监控,Prometheus采取的立场是,您的监控通常可靠且可用,而不是100%准确,这一点更为重要。对于基于指标的监控,99.9%的准确率适用于大多数用途。对于您来说,知道延迟增加一毫秒比增加到101.2或101.3毫秒更有用。只要您的范围至少是收集间隔的四倍,速率就可以抵抗偶尔失败的收集,如“速率”中所述。

在讨论可靠性时,您应该问的第一个问题是您需要监控的可靠性如何?如果您正在监控具有99.9%SLA的系统,那么花费您的时间和精力来设计和维护99.9999%可用的监控系统是没有意义的。即使你可以构建这样一个系统,你的用户使用的互联网连接,以及在线呼叫的人的响应都不可靠。在这种情况下,我想谈谈可靠的警报。如果Prometheus由于某种原因死亡,你应该让它自动重启,并且中断应该是最小的状态重置,但是如果机器Prometheus在模具上并且Prometheus无法重启,你就赢了直到你更换警报。如果您正在使用诸如Kubernetes之类的集群调度程序,您可以预期这会很快发生,这可能就足够了如果替换是一个更加手动的过程,这可能是不可接受的。

好消息是,通过消除单点故障(SPOF),您可以轻松地使警报更加可靠。如果您运行两个相同的Prometheus服务器,那么只要其中一个服务器正在运行,您就会收到警报,并且Alertmanager会自动对警报进行重复数据删除,因为它们将具有相同的标签。我现在已经多次提到外部标签应该在所有Prometheus服务器上都是唯一的。这样,如果在前一个设置中有多个Prometheus服务器并且您正在使用它们进行远程写入或联合,则来自不同Prometheus服务器的度量标准不会发生冲突。即使在完美的条件下,不同的Prometheus服务器也会看到略有不同的数据,例如,这些数据可能被误解为计数器重置。在不太理想的条件下,例如网络分区,每个冗余的Prometheus服务器都可以看到截然不同的信息。

这让我想到了仪表板,联合和远程写入的可靠性问题。没有通用的方法可以自动从不同的Prometheus服务器中合成“正确”的数据,而通过Grafana或联合的负载均衡器会导致伪像。我建议采用简单的方法,只使用Prometheus服务器之一的仪表板/联合/写入,如果它已经关闭,那么就要有差距。在极少数情况下,差距将涵盖您关注的时期,您可以随时手动查看其他Prometheus中的数据。对于全局Prometheus服务器,权衡有点不同。 由于全局Prometheus服务器正在监控故障区域,因此,如果数据中心出现严重停电,则全局服务器可能会停机数小时或数天。 这对于数据中心Prometheus服务器来说很好,因为它们没有运行,但它们都不会监视它们。 我建议您始终在不同的数据中心和仪表板中运行至少两个全局Prometheus服务器,从而使所有全局服务器都可以使用图表。 类似地,对于远程写入,使用仪表板的人员有责任解释来自不同来源的数据。

Alert Manager 集群

您需要为整个组织运行一个集中的警报管理器设置,以便每个人都有一个地方可以查看警报和静音,并从警报分组中获得最大的好处。除非您有一个小型设置,否则您将利用警报管理器的集群功能。警报管理器的集群架构警报管理器使用Hashicorp的成员列表来发送有关通知和静音的信息。这不是基于共识的设计,因此不需要有奇数个Alertmanagers。这就是所谓的AP,即可用性和分区容忍设计,因此只要您的Prometheus可以与至少一个可以成功发送通知的警报管理器通信,您的通知就会通过。当存在诸如网络分区之类的罕见问题时,您可能会收到重复通知,但这比完全不注意通知要好。为了使集群正常工作,每个Prometheus都必须将其警报发送给每个警报管理器。工作原理是警报管理员自行订购。第一个警报管理器正常发送通知,如果成功,则说明通知已发送。第二个警报管理器在发送通知之前有一点延迟。如果没有得到第一个警报管理器发送通知,那么它将发送通知。第三个安德曼管理员将有一个稍长的延迟,依此类推。警报管理器应该都具有相同的alertmanager.yml文件,但如果它们不存在则最糟糕的情况是将发送重复通知。测试集群是否正常工作的最简单方法是在一个警报管理器上创建一个静音,看看它是否出现在另一个警报管理器上。还可以在Alert Manager的Status页面上找到集群所有成员的列表。

查找瓶颈指标和收集目标

查找具有高基数的指标。您还可以按作业聚合,以查找哪些应用程序负责最多的时间序列。但这些可能是非常昂贵的查询,因为它们触及每个时间序列,因此应谨慎使用。除此之外,Prometheus还为每个目标收集加了三个其他样本。 scrape_samples_scraped是/ metrics上的样本数。由于这是每个目标的单个时间序列,因此使用它比以前的PromQL表达式快得多。 scrape_samples_post_metric_relabeling类似,但它不包括由metric_relabel_configs删除的样本。添加的最后一个特殊样本是scrape_duration_seconds,这是收集花了多长时间。这可用于检查超时是否达到超时值时发生超时,或作为目标过载的指示。

HASHMOD

如果你的Prometheus被来自收集的数据所超载而无法运行查询,那么有一种方法可以去掉一部分目标。还有另一个名为hashmod的relabel动作,它计算标签的散列并获取其模数。结合drop relabel动作,您可以使用它来去掉任意比例的目标。只有一定比例的目标要拉取,如果你可以启动测试Prometheus,你现在应该能够找出应该责怪哪个指标。如果它只是导致问题的一些目标,则可以通过将正则表达式更改来更改哪个目标要去掉,依此类推。

减少负荷

一旦确定了昂贵的指标,您就有了一些选择。首先要做的是尝试在源代码中修复度量标准以降低其基数。当你等待这种情况发生时,你有几个战术选择。第一种是使用metric_relabel_configs将度量标准放在摄取时间。这仍然会通过网络传输指标并对其进行解析,但它仍然比将其提取到存储层更便宜。如果特定应用程序存在问题,您也可以通过重新标记删除这些目标。

最后一个选项是增加Prometheus的scrape_interval和evaluation_interval。这可以为你带来一些喘息的空间,但请记住,将它们增加到超过2分钟是不切实际的。更改scrape间隔也可能会破坏依赖于具有特定值的某些PromQL表达式。scrape配置中还有另一个选项,可以用来称为sample_limit。如果metric_relabel_configs26之后的样本数高于sample_limit,则scrape将失败并且不会摄取样本。默认情况下会禁用此功能,但如果您的某个目标在基数中爆炸,例如通过添加带有客户标识符的指标作为标签,则可以充当紧急安全阀。这不是微观管理或尝试建立某种形式的配额制度的设置;如果你打算使用它,选择一个很少需要碰撞的慷慨值。我建议在你的Prometheus有足够的缓冲空间来处理基数和目标的适度冲刺。

水平分片

如果由于实例基数而不是仪器标签基数而遇到扩展挑战,有一种方法可以使用您在“Hashmod”中看到的hashmod relabel操作来水平分割Prometheus。这种方法通常只有在单一类型的应用程序中有数千个目标时才需要,因为垂直分片是扩展Prometheus的一种更简单的方法。水平着色的方法是拥有一个Prometheus主节点和几个Prometheus拉取。您的抓取Prometheus服务器每个都会去拉取一部分目标。

所有与联邦相同的问题,这不是让一个Prometheus可以让您透明地访问所有Prometheus服务器的方法。事实上,通过一个昂贵的查询同时取出所有监控实际上是一种很好的方式。使用它时,最好聚合拉取器的内容以减少主机需要从拉取器提取的数据量。你应该对拉取器的数量很慷慨,并且每隔几年就要增加一次。当你增加它时,你应该至少加倍它数量,以避免不久再次增加数量。

管理变更

随着时间的推移,您会发现由于系统架构的变化,您需要更改目标标签的结构。随着应用程序拆分和合并作为开发的自然部分,哪些应用程序将承载用于容量规划的度量标准将随时间而变化。度量标准将在发布到发布时出现和消失。

您可以选择使用metric_relabel_configs重命名度量标准,并将新层次结构塞入现有目标标签中。但随着时间的推移,你会发现这些调整会累积并最终导致更多的混乱,而不是试图通过试图保持相同的东西来防止。我建议接受这样的改变是你系统演变的一个自然部分,并且由于拉取失败造成的差距,你通常会发现你不关心事后的旧名称。另一方面,诸如容量规划之类的长期过程确实关心历史。至少你应该注意一段时间内指标的名称,并且可能考虑使用全局Prometheus的“API规则”中的方法,如果这些更改太频繁而无法手动管理。