博客/工程

介绍了用Grafana Tempo和Grafana药剂进行痕量采样的方法

2022年5月11日17分钟

各位朋友,你们好!

在现场工程团队,我们经常被问到追踪。两个经常出现的问题:我需要采样吗?而且我如何取样我的痕迹?问这个问题的人通常使用跟踪存储,在这里根本不可能存储生成的所有跟踪。

这些都是很好的问题,答案取决于几个不同的因素。

Grafana节奏Grafana云的痕迹,Grafana企业痕迹都是高度可伸缩的、具有成本效益的解决方案,专门设计用于在您的基础设施和应bob彩票中奖计划用程序中存储所有跟踪,而根本不需要进行任何采样!它们不仅为希望立即观察数据如何流经其服务的用户带来了巨大的好处,而且还帮助工程师和SREs(他们可能希望回到上周或几周前)将历史痕迹与当前状态进行比较。这允许他们发现潜在的优化和数据流中的瓶颈。

然而,有时您并不需要所有的痕迹。这可能是因为您对通过系统的特定请求不感兴趣,比如持续时间少于任意数量的请求;没有导致错误的请求;甚至是到达特定端点的请求,而您根本不关心这些请求。

因此,在确定是否需要抽样时,组织应该问以下几个问题:

  • 有没有一个很好的理由不存储我们所有的痕迹?
  • 如果我们不发送所有的踪迹,我们会错过什么?
  • 我们的系统或基础设施中是否存在我们从来不需要跟踪的部分?
  • 有没有我们根本不关心的痕迹?

如果其中任何一个问题的答案是“是”,那么您可能希望执行某种跟踪采样。

当然,你可能会有一个更基本的问题:什么跟踪采样?

尾部抽样的介绍

当应用程序使用跟踪SDK(例如OpenTelemetrySDK中,它发出组成单个跟踪的跨度。通常,跟踪是基于进入系统的单独的、惟一的请求,然后在响应发送回请求者之前进行处理。这允许对接收到的每个请求进行单独观察,这对于发现错误、延迟和其他影响用户的因素非常有帮助。

例如,如果您一秒钟有一个请求,这相当于一分钟60个请求或一天86,400个请求。那是……请求不多。如果我们考虑一个SaaS解决方案,它可能包含20个独立的微服务,每个服务有几个跨,每个跨大约300字节,那么每个跟踪大约有40个跨,每个跨300字节——或者一个跟踪12KB。所以在一天的时间里,您需要大约1gb的跟踪存储空间。

好吧,每天1gb并不算多。你可以把它储存起来,并很容易地查看这些痕迹。然而,如果您每天只收到86,400个请求,那么可能会发生非常严重的情况:您将因为没有足够的客户而倒闭。

大多数常见的SaaS解决方案每秒都bob彩票中奖计划会收到数万甚至数十万个请求,如果不是数百万个的话。12000字节(用于单个跟踪)乘以100万,乘以60x60x24,这个数字太大了,我甚至不打算用计算器计算。要实际处理这么多跟踪并存储它们,不仅在CPU和内存资源方面,而且在存储方面也非常昂贵。

正因为如此,现在许多跟踪解决方案都使用某种类型的采样来减少传输和存储bob彩票中奖计划跟踪的负担。这可以采取从特定数量中只捕获一个跟踪的形式(例如,100分之一),并被称为概率随机抽样.这背后的理论是,在发出如此多的跟踪的情况下,仅对其中的一小部分进行采样仍将确保您能够看到与您相关的跟踪,例如抛出错误的请求,或具有特定最小持续时间的请求。

许多解决方案比这更bob彩票中奖计划聪明,实际上使用更高级的抽样。他们使用检测异常和偏离他们所认为的“正常”跟踪的技术,以确保捕获和存储异常值。虽然这种方法很有效,但有时会遗漏重要的痕迹,这也是我们Grafana实验室认为捕获所有痕迹非常重要的原因之一。bob电竞频道

头部抽样和尾部抽样

抽样通常有两种不同的形式。

抽样的两种形式
抽样的两种形式

头抽样通常发生在仪器化的应用程序中。这种类型的采样决定是否应该在跟踪生命周期的早期捕获跟踪。例如,假设您的健康检查端点只返回“ALIVE!”任何请求。这可能不是您真正关心的代码。(这是一个谎言——你关心它,但考虑到它可能不是一个非常复杂的函数。你只是想确保它工作,而不是跟踪它。)

当由于对该端点的请求而创建一个新的跟踪时,您可以在端点处理程序中编写一些代码,指示跟踪工具不再继续跟踪。不会将任何跨度发送到您正在使用的跟踪存储区,并且为该跟踪创建的任何进一步的跨度将被忽略。在跟踪的开头已经做出了忽略它的决定,而不管是否有进一步的跨度。

你可能已经猜到了,尾巴抽样发生在跟踪的末尾——即,当一个跟踪的所有跨度都已发出且跟踪已完成时。这通常不会发生在应用程序插装中,因为微服务的复杂性意味着跟踪可能会在下游服务中从发起跟踪的地方结束。相反,尾部采样通常发生在跟踪存储后端,或者更常见地发生在本地运行的代理或在应用程序基础结构中操作的跟踪收集器中。

因为尾采样要等到接收到跟踪的所有跨度,所以它可以基于整个跟踪做出决策。依赖于跟踪的所有跨度,它将只存储在所存储的任何跨度中显示错误的跟踪;有最短持续时间的;甚至是跨包含特定标记和属性的跟踪。它甚至可以只做简单的随机抽样!

也就是说,尽管尾部采样比头部采样灵活得多,但它也需要更多的资源,因为它需要遍历跟踪的所有跨度,以应用所需采样类型的逻辑。因此,应该慎用。

用Grafana剂进行尾部取样

此时,您可能已经很清楚是否需要进行抽样,以及抽样什么。你的下一个问题可能是:你能在发送痕迹到Grafana Tempo, Grafana Enterprise traces或Grafana Cloud traces之前取样吗?

是的!

Grafana代理通用的可观察性收集器是可以刮的吗普罗米修斯度量,捕获日志,并将它们发送到洛基,并从任何Tempo兼容的仪器SDK(例如,OpenTelemetry, Jaeger, Zipkin等)接收跟踪。

Grafana Agent还包括许多用于处理跟踪的功能,例如从传入的跟踪范围发出的速率、错误和持续时间(RED)度量;自动生成输入轨迹的日志线;从流行的自动发现添加标签(如k8s细节);当然,还有尾部抽样。

因为它符合OpenTelemetry SDK标准,Grafana Agent还包括OpenTelemetry指定的所有尾部采样策略。(你可以找到这些在这里尽管要获得支持的采样策略的最新视图,还是有必要查看一下代码在这里.)

一些流行的抽样政策是:

  • 跟踪时间
  • Span标签/属性值
  • 带有标记错误的span

正如我已经指出的,能够跟踪采样要求跟踪的所有跨度都是可用的。但是,如果您的服务非常大,并且运行多个代理,会发生什么情况呢?在这种情况下,您可能希望在轮询(或其他负载平衡)配置中运行Grafana Agent。这意味着可以将特定跟踪的跨度潜在地发送到不同的代理。这很快就成为一个问题,因为即使这些跨度仍然可以被后端存储(Tempo、GET、Grafana Cloud Traces)组合成单个跟踪,它也会阻止发生尾部采样。

不要害怕!Grafana Agent包含一个配置选项,允许跨所有已知代理进行负载平衡。它确保跨度总是由单个代理处理,并且可以通过已知代理的静态列表或通过返回代理ip列表的DNS记录进行配置(例如在无头Kubernetes服务中)。这使得即使在多个Agent实例中也可以进行尾采样。需要注意的一点是,这确实使用了额外的资源——span信息最多可以发送两次,以便正确的Agent进行处理。

看到load_balance部份Grafana Agent配置指南更多信息。

一些实际的例子

我已经絮絮叨叨了这么久,你可能在想,“他什么时候才会有好东西?”好吧,抓住你的帽子、头发或头皮,因为我们将深入研究一些有用的例子。

我是那种"看,做,记"的人,主要是因为我年纪大了开始走神有点像戴夫·鲍曼2001太空漫游穿过星际区。

因此,这里的示例是交互式的。如果你还没有安装,你需要安装:

  • Git
  • Docker和Docker Compose

安装好工具之后,克隆git存储库(假设你有一个与Github相关的SSH密钥):

Git克隆Git +ssh://github.com/grafana/opentelemetry-trace-sampling-blogpost.git CD opentelemetry-trace- sample -blogpost

这个库有一个Docker Compose文件,包括:

  • Grafana(可视化数据)
  • Grafana节奏(存储和查询跟踪
  • Grafana洛基(存储和查询日志)
  • Grafana代理(在发送到Tempo之前处理跟踪数据)
  • 一个演示应用程序来显示跟踪采样,它:
    • 发送跟踪到Grafana代理
    • 直接发给洛基(我们可以用码头工人司机对于这个,但它节省了额外的复杂性,让我们容易添加一些标签)

你可以通过使用标准的Docker Compose功能从命令行启动项目:

docker-compose起来

这将建立所有组件,为应用程序构建一个小型Docker映像,然后执行它。

让我们快速浏览一下Grafana。一旦启动,登录到Grafana:

http://localhost:3000

使用以下凭证:

用户:管理员

密码:admin

已经预先准备了两个数据源:Tempo和Loki。Loki包含演示应用程序的日志输出—包括跟踪id—Tempo存储跟踪。在开始时,演示应用程序发出的所有跟踪都被存储。我们可以通过在Grafana和中的Explore页面快速验证这一点在看所有的日志

探索日志
探索日志

让我们通过展开一些对数线来查看一些跟踪:

节奏按钮
节奏按钮
跟踪查看
跟踪查看

这里我不打算详细介绍如何可视化跟踪,因为有很多跟踪博客文章用Grafana详细追踪。

目前,正在捕获来自应用程序的所有跟踪。因为在将跟踪发送到Tempo之前,我们使用Grafana Agent来整理和批处理这些跟踪,因此配置Agent来捕获它们并将它们远程写入后端非常简单。

找到代理/ config.yaml归档并在您最喜欢的代码编辑器中打开它。它看起来是这样的:

Server: log_level: debug traces: config:—name: server_traces servers: otlp: protocols: http: endpoint: "0.0.0.0:4318" remote_write:—endpoint: tempo:4317 insecure: true

简单地说,这指示代理以调试模式记录所有内容,并创建一个新的跟踪配置部分,该部分将从应用程序接收OTLP格式跟踪。然后,它将它们写入您正在运行的Tempo实例。

我们将向配置文件添加一个新部分。Grafana Agent使用OpenTelemetry尾部采样处理器,因此支持OpenTelemetry收集器提供的所有采样策略。

让我们做一个明显的改变,使用尾部抽样来确保我们只接收有错误的跟踪。

你是怎么做到的?那么,您需要知道如何为进入Agent的跟踪过滤跨度数据,以便它只标记那些有错误的跟踪。幸运的是,有一个OpenTelemetry规范中的约定这包括设置一个span的状态码。这意味着,对于发生错误的地方编写的任何代码,都可以在该点生成的范围上设置错误状态,这将标志发生了错误。通常,设置特定的错误代码和消息来详细说明出错的地方也很有用。

如果我们快速浏览一下应用程序的代码src / index.js下面的文件),我们可以看到这正是发生的情况:

let spanStatus = api.SpanStatusCode.OK;if (dbError) {spanStatus = api.SpanStatusCode.ERROR;dbSpan。setAttributes ({db。错误':'INVALID_DATA', 'db. data '。error_message': '发送到数据库的数据无效',});dbSpan.}setStatus({code: spanStatus});

我专门在这个跨度上设置错误代码状态,并将额外的错误信息作为属性。这还确保父span上设置了一个错误,以便将此信息沿链向上渗透。稍后可以在代码中看到它。

方法上的span搜索功能来搜索错误,我们可以在实际操作中查看这一点Tempo数据源在Grafana.通过搜索具有适当状态代码集的区间,您可以看到在其中抛出错误的所有跟踪。

使用跨度搜索功能搜索错误
使用跨度搜索功能搜索错误

这很容易转化为代理中的尾部抽样过滤器。返回到它的开放配置代理/ config.yaml文件),并添加一个新部分(注意这需要与remote_write):

tail_sampling: policies:—status_code: status_codes:—ERROR

这个配置块做了几件事。它首先表示我们在定义atail_sampling部分,然后它将包含一个或多个策略(您可以同时定义多个策略)。的status_code策略接受一个名为status_code,它定义了存储跟踪所需的代码。目前这些值是:设置错误而且好吧.在本例中,我们只想存储跨度为错误代码集。

在另一个命令行终端中,运行以下命令重新启动Agent:

docker编写重新启动代理

这将使用新的尾部采样策略重新启动代理。在这一点上,可能值得泡一杯茶(或您选择的饮料),既为了休息,也因为如果您让系统运行几分钟,就会清楚得多,您现在只收集有错误的痕迹!

让我们回到Grafana实例来查看更改。我们会讲到跟踪的日志(虽然我们也可以很容易地在Tempo可视化工具中使用跨度搜索功能‘search - Beta’,就像我们之前所做的那样)。展开未发生错误的日志行(任何绿色条目)的详细信息。点击Tempo按钮,你会看到如下内容:

扩展了日志行的详细信息
扩展了日志行的详细信息

尽管我们有一条表示事件的日志行,并且应用程序检测了跟踪,但是您在Tempo面板中看到查询错误的原因是Grafana Agent使用了它的尾部采样策略来丢弃跟踪,因为其中没有一个跨的状态码设置为错误。您可以通过找到标记有错误的日志行(用红色条目表示)并选择节奏按钮转到相关的跟踪,这将会存在。

通过span标记进行筛选

另一个有用的过滤器是只收集有用端点的跟踪。大多数服务都有运行状况检查(或“ping”)端点,可用于确定服务是否启动。我们的应用程序跟踪的端点之一是/ healthcheck.我们还得到了一些度量端点—同样,我们不太关心跟踪。让我们创建另一个尾部抽样策略忽略这两个。

回到编辑器中的Grafana Agent配置,并删除我们为捕获错误创建的策略。相反,用下面的块替换它:

—string_attribute: key: http。目标值:—^\/(?:metrics\/.*|healthcheck)$ enabled_regex_matching: true invert_match: true

这将定义一个类型的新策略string_attribute.该策略需要一个span标记/属性键进行筛选,在本例中查找http.target属性,该属性表示被请求的端点。的Array允许您设置一个或多个值,这些值与string属性键的值相匹配。如果匹配,则存储跟踪。在这种情况下,我们决定与/标准/ *而且/ healthcheck端点。

现在,在这一点上,您可能会想,“等等——如果匹配发生在这些值上,那么这些跟踪将被存储……这实际上与我们想要的恰恰相反!”

这是正确的!令人高兴的是,这种策略类型包含一个invert_match布尔选择器,这意味着只存储跨度与我们的值不匹配的跟踪。运行状况检查和度量端点的跟踪实际上将被丢弃。

您可以通过以下命令行终端重新启动代理:

docker编写重新启动代理

同样,让系统运行几分钟,然后让我们为运行状况检查找到一些踪迹Loki中使用LogQL的度量端点

使用LogQL查找跟踪
使用LogQL查找跟踪

此LogQL查询确保您只找到与相关的日志行/ healthcheck/标准/ *.选择这些条目中的任何一个,然后试图找到与之相关的跟踪都会失败,因为您已经过滤掉了这些跟踪。

如果你寻找其他的对数线,使用我们使用过的LogQL查询的反转,您将发现其他端点的所有跟踪都已存储。

太棒了!您现在知道了如何创建两个单独的策略来收集错误并过滤特定的端点。但是如何确保只看到所关心的端点上的错误呢?

OpenTelemetry还包含一些策略,允许您组合其他策略。其中之一是“and”策略,顾名思义,它允许您将策略与组合成一个超级策略。

再次编辑Agent配置文件,并将尾部采样块替换为以下内容:

Tail_sampling: policies:—and: and_sub_policy:—name: and_tag_policy type: string_attribute string_attribute: key: http。目标值:—^\/(?:metrics\/.*|healthcheck)$ enabled_regex_matching: true invert_match: true- name: and_error_policy type: status_code status_code: status_codes: - ERROR

在这里,您使用“and”策略将前面的两个策略合并为一个策略。现在,您将只能看到跨度表示发生了错误的跟踪,而这些错误既不在指标上也不在运行状况检查端点上。

再次,在另一个终端窗口中使用以下命令重新启动代理:

docker编写重新启动代理

现在您可以安全地确保只存储来自您关心的端点的错误!您可以通过返回Grafana轻松检查这是否有效。您应该会看到,只有对运行状况检查和度量端点上没有发生的错误的跟踪是可用的。

更多跟踪采样策略

这是一个使用Grafana Agent进行尾部抽样的简单介绍,但值得注意的是,状态代码和跨度属性策略只是两个基本示例。事实上,还有几个非常有用的抽样策略:

  • 概率抽样(有时称为随机抽样)允许您只存储1在 探员看到的痕迹。
  • 延迟过滤器确保只存储占用一定时间的跟踪。
  • 数值跨度属性检查允许您只存储属性值介于最小值和最大值之间的跟踪。
  • 速率限制每秒钟最多存储一定数量的跟踪。
  • 复合策略将传入跟踪率的百分比分配给子策略。

这些已经足够确保您可以执行几乎所有可能需要执行的跟踪过滤。

抽样快乐!

Grafana云是开始使用度量、日志、跟踪和仪表板的最简单方法。我们对每个用例都有一个慷慨的免费永久层bob体育手机二维码和计划。现在就免费注册