博客/工程

隔离如何改进普罗米修斯2.17中的查询

2020年5月5日5分钟

在生活中,有时孤独是受欢迎的。

其中一个例子与首字母缩写中的I有关,概述了维护数据库中事务完整性所需的关键属性。嵌入在Prometheus服务器中的时间序列数据库(TSDB)具有C(一致性)、D(持久性)和A(原子性)(这有点争议)。

但直到现在普罗米修斯v2.16,它没有I(隔离)。在Prometheus上下文中缺乏隔离意味着与抓取同时运行的查询只能看到抓取中摄取的样本的一小部分。它需要正确的时机和正确的查询来实现。即使它真的发生了,其影响通常也很难被注意到。

但有时,这会导致非常奇怪的结果。因为原因是如此难以找到和理解,它可能会对你造成非常严重的打击。

最常见的问题是直方图。的histogram_quantile函数遍历直方图的桶,如果其中一些桶来自当前的刮擦,一些来自前一个,它将严重地偏离轨道。

你可能从我的上一篇博文直方图是普罗米修斯宇宙中我最喜欢的主题之一。因此,我非常高兴在三月份发布的Prometheus TSDB 2.17版本中最终添加了隔离。

背景

所有的基础工作,它背后的理论,以及隔离的最初实现都是由普罗米修斯团队成员布莱恩巴西。他在报纸上解释了一切下半年他史诗般的演讲《普罗米修斯2.0》中的陈腐与孤立PromCon 2017.我衷心建议大家关注这个视频。它很密集,但我无法更好地解释它。

从那时起,该理论并没有真正改变,但您可能已经注意到,隔离功能并没有进入2.0版。不知怎么的,原始拉请求很快就被遗忘了。一年后,高Veeramachaneni,另一名普罗米修斯团队成员和我在Grafana实验室的同事bob电竞频道)在大学的一个项目中学会了它。但是,新的公关和前一个一样的命运。

在我的追寻中更好的普罗米修斯直方图,我给了那个PR一个第三种生活.从原则上讲,这并不是什么大工作。我“只”需要调整代码以适应在另外两年繁忙的开发中所发生的变化,并且我必须查找一些错误。但现在它终于完成了,故事有了一个幸福的结局。

但是天下没有免费的午餐。隔离带来了一定的代价,比如稍微增加的CPU使用、内存使用和查询延迟。在大多数情况下,您可能不会注意到这些变化。然而,当巨大的性能倒退报告在v2.17发布之后,我的心跳了一拍。幸运的是,它来自另一期,那是及时修复并发布为v2.17.1。

孤立的影响

在家也很容易尝试。通过简单的设置,您可以观察隔离的效果(以及缺乏隔离的情况)。

首先,你需要一个测试目标。如果你有一个工作的Go开发环境,你可以运行一个例子普罗米修斯/ client_golang

$ GO111MODULE=on去获得github.com/prometheus/client_golang/examples/random@v1.5.1 $ random

您可以在浏览器中检查示例目标的指标输出旋度)使用网址http://localhost:8080/metrics

现在您需要一个Prometheus配置文件来获取测试目标。实际上,我们并行地做了五次,以使它更有可能遇到隔离问题。将以下内容放入名为prometheus.yml

Global: scrape_interval: 101ms evaluation_interval: 11ms rule_files: - "demo-rules. "Yml " scrape_configs: - job_name: 'example1' static_configs: - targets: ['localhost:8080'] - job_name: 'example2' static_configs: - targets: ['localhost:8080'] - job_name: 'example3' static_configs: - targets: ['localhost:8080'] - job_name: 'example4' static_configs: - targets: ['localhost:8080'] - job_name: 'example5' static_configs: - targets: ['localhost:8080']

注意这有点奇怪scrape_interval而且evaluation_interval.这些数字是精心设计的,再次使它更有可能遇到隔离问题。从本质上讲,它们使规则计算非常频繁地发生在抓取周期的各个阶段。此外,配置引用一个规则文件demo-rules.yml.用以下内容创建它:

组:- name: demo rules: - record: this_should_not_happen expr: |2 irate(rpc_durations_histogram_seconds_bucket{le="-8.999999999999979e-05"}[1s]) > ignoring (le) irate(rpc_durations_histogram_seconds_bucket{le="1.0000000000000216e-05"}[1s])

该规则检查示例目标公开的直方图中的两个桶。如果持续时间较短的桶比持续时间较长的桶具有更高的计数,那么我们就遇到了一些本不应该发生的事情。(记住:普罗米修斯直方图是累积的。)假定的原因是:由于缺乏隔离,规则计算看到持续时间较短的桶的更新版本,并将其与持续时间较长的桶的旧版本进行比较。

您可以通过运行未实现隔离的最新Prometheus版本(v2.16.0)来测试它。以您喜欢的方式运行带有上面所述创建的文件的Prometheus服务器版本。使用Docker特别简单:

$ docker run——net=host -v $(pwd):/etc/prometheus prom/prometheus:v2.16.0

让它运行几分钟,然后执行查询总和(count_over_time (this_should_not_happen [1 m]))在一个内置表达式浏览器的选项卡。你会看到如下内容:

v.2.16.0中没有隔离的普罗米修斯图
v.2.16.0中没有隔离的普罗米修斯图

该查询计算每分钟的计算次数this_should_not_happen创建结果。

现在让我们拿出v2.17,再次尝试同样的事情:

$ docker run——net=host -v $(pwd):/etc/prometheus prom/prometheus:v2.17.2

你想放多久就放多久。与上面相同的查询结果总是如下所示:

v.2.17中普罗米修斯与隔离的图
v.2.17中普罗米修斯与隔离的图

不该发生的事,不会再发生了。任务完成!