博客/工程

一个(de)bug的生命:诊断和修复Grafana Loki读路径中的性能问题

2022年1月24日6分钟

哔,哔,哔读取路径SLO页面,再一次.我快找到那个吵闹的邻居了!

那是我。也许在未来的某个时候,我还是我。随着我们继续扩大构建和运行团队的规模Grafana洛基在Grbob电竞频道afana实验室,我决定记录下我如何发现和诊断洛基的问题。这将一举多得:它迫使我写下我在调查中看到的模式,并且我可以与之分享这些知识我们不断壮大的团队以及我们的社区——那些在工作、家庭或任何地方管理洛基的人。

在这里,我将回顾一下我为Grafana云日志为了说明我们如何定期使用度量来为我们指出正确的方向,然后如何使用日志来验证我们的猜测。

在下面概述的场景中,一个租户过度消耗资源,降低了所有人的工作速度。本案例研究使用了Grafana仪表板,普罗米修斯以及运行在Kubernetes集群中的Loki。

发现问题

当我们的团队接到呼叫时,我们要做的第一件事是弄清楚我们要查看的是什么类型的问题。基本上,这些请求是完成的还是slooow?一堆HTTP 5xx比一些缓慢的查询要可怕得多,所以让我们从这个角度来解决这个问题。

我们将从检查Loki / Reads指示板,已包含在loki-mixin

看起来在这段时间里,我们的QPS(每秒查询量)几乎停止与此同时,我们的延迟时间直线上升。这让我觉得我们的读路径阻塞了,导致查询排队,并导致执行的查询非常慢。我们注意到,在此激增期间,所有查询类型的延迟都增加了,这支持了这样的观点:要么没有足够的查询器,要么查询器过载。

接下来,让我们转向洛基/阅读资源指示板,这也包括在loki-mixin.这个仪表板显示资源使用情况:

啊,内存真大啊!在这段高资源使用期间,查询器荚似乎直接达到了它们的极限。再次转向洛基/正常运行指示板,我们还可以看到这会导致一堆查询器重新启动!

这只会让情况变得更糟。

此时,我非常确信我们的读路径完全被昂贵的查询所饱和,这些查询导致查询器由于内存不足而重新启动。这反过来又阻止了其他租户使用这些资源,直到查询器重新启动。之后,我们在查询调度器中看到更多的查询在队列中等待:

立即采取行动

我们已经确定了堵塞的症状,那么我们应该采取什么应对措施呢?看看等待请求的队列,向外扩展读取路径是个好主意,尤其是查询器。这将提高Loki集群的查询处理能力,并在短期内帮助减轻一些负载。

追查罪魁祸首

在添加了一些查询器节点之后,我们使用相同的仪表板注意到问题并没有消失。即使我们添加了查询器,成功处理的QPS的数量也没有改变。这是一个很大的迹象,如果我们增加了高速公路上的车道,但更多的汽车无法通过,很可能会出现交通堵塞。

我的第一个想法(只是因为我以前经历过这种情况)是,可能某个租户提交的查询逃脱了我们的噪声邻居控制。在一个多租户环境中,我们无法区分分配给一个租户和另一个租户的内存或CPU的数量,如何识别问题呢?

我们将首先转到Grafana仪表板,选择Prometheus指标的适当时间范围,然后使用“Explore”来捕获时间范围:

在适当的时间范围内,切换到Loki数据源,从同一时间段的查询器日志中提取一些指标。这些指标将帮助我们回答以下问题:哪些租户在集群的读路径上消耗了最多的处理时间?下面是LogQL查询:

#谁正在吃读路径>:(topk(10, sum(sum_over_time({cluster="", namespace="", container=" querer "} |= "metrics. "输入" | logfmt | unwrap duration(duration) [5m]) by (org_id))

查询结果显示了以下内容。租户标识符省略:

正如我们在这张图中看到的,一个租户从其他租户中脱颖而出!然后,我用< cluster >、< namespace >和< offending_tenant >字段填充运行这个LogQL查询,以查看正在运行的查询类型:

{cluster="", namespace="", container="query-frontend"} |= "metrics. "去" | logfmt | org_id=""

事实证明,有许多代价高昂的查询具有极长的回溯间隔。认为Quantile_over_time (0.99, {foo= " bar "} | json | unwrap duration(response_time) [7d]).Loki将查询按时间分割,然后需要为每个数据点处理7天的数据,其中大部分数据被重用。尽管我们将时间间隔划分为大约30分钟,但每个30分钟的时间段都需要获取过去7天的日志。

瞧!我们有根本原因。

缓解

在短期内,我们可以:

  • 放大读路径。
  • 减少违规者的租金max_query_parallelism因此,它们不能一次安排尽可能多的查询,从而为相邻的租户释放更多的读取路径。
  • 建议他们对这些重复的、昂贵的查询使用记录规则。

从长远来看,我们可以:

  • 放大读路径。
  • 更好地测量读取路径,以更快更深入地识别/理解这些问题。我打开了这个公关在这个调试会话之后!
  • 寻找更有效的方法来并行处理这些昂贵的查询,特别是那些间隔很长的查询。
  • 实现更好的QoS(服务质量)控制,使一个租户在集群处于负载状态时更难以过度消耗其公平的资源份额。

分开的想法

这可真够写的。谢谢你走了这么远!我总是低估记录问题和解决方案的难度,但我希望它能帮助其他人更快地理解我的思维过程并解决日志问题。bob彩票中奖计划

作为奖励,我将留下一个更有趣的问题。(请不要嘲笑我对“乐趣”这个词的定义。)

# out of slo instant queries by tenant sum(count_over_time({cluster="prod-us-central-0",job="loki-prod/query-frontend"} |= "metrics. "输入" | logfmt | range_type="instant" and duration > 10s [1h]) by (org_id) / on () group_left sum(count_over_time({cluster="prod-us-central-0",job="loki-prod/query-frontend"} |= "metrics. "执行" | logfmt | range_type="instant" and duration > 10s [1h])) * 100

该查询告诉我们slo外即时查询的百分比可归因于哪个租户。今天,我使用这个方法取得了很大的效果,发现我们有一个租户在一个小时内负责98%的slo外即时查询!

入门格拉夫娜·洛基最简单的方法就是Grafana云.我们有一个慷慨的免费永久层,为每个用例bob体育手机二维码提供50gb的日志和计划。现在免费注册