活跃序列
活跃序列是接收新数据点或样本的时间序列。当您停止向时间序列写入新数据点时,不久后它将不再被视为活跃序列。
指标生成器生成的指标可以提供 RED(速率/错误/持续时间)指标以及分布式追踪中服务之间的相互依赖图(Grafana 中的服务图功能)。这些功能依赖于一组生成的 Span 指标和服务指标。
Tempo 摄取的任何 Span 都可以创建许多指标序列。然而,这并不意味着每次摄取 Span 都会创建一个新的活跃序列。
生成的活跃序列数量取决于与指标关联的 Span 数据生成的标签对,与其他 Prometheus 格式的数据类似。
更多信息,请参阅活跃序列和 DPM 文档。
活跃序列计算
当引入标签键的新值时,指标的活跃序列会增加。例如,span_kind
标签总共有五个可能的值,而 status_code
标签总共有三个可能的值。
乍一看,您可能会认为这意味着每个 Span 至少会生成 15 (5*3) 个活跃序列。但事实并非如此。
让我们考虑一个从服务中某段代码发出的 Span
这里有一个包含单个 Span 的服务。如果 Span 内部的代码从未离开该服务,则指标生成器生成的 span_kind
标签将始终是 SPAN_KIND_INTERNAL
且不会改变。它永远不会是其他四个可能值之一。
类似地,如果 Span 内部的代码从不报错,则 span_status
标签将始终处于 STATUS_CODE_OK
状态。这意味着指标生成器只会生成一个活跃序列,其中服务名称为 Service 1,Span 名称为 span1。如果查看 traces_spanmetrics_call_total
指标的 Prometheus 数据,您会看到一个活跃序列
服务 | span_name | span_kind | status_code | 指标值 |
---|---|---|---|---|
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 1 |
无论该 Span 在分布式追踪中出现多少次都无关紧要,例如,Span 可能会在循环中生成。无论代码运行一次、10 次、100 次还是 1000 次,只会产生一个活跃序列,其中计数器可能会增加 1、10、100 或 1000 次
如果查看 Prometheus 数据,您会看到一个与表中类似的 traces_spanmetrics_call_total
即时值。同样,该指标只有一个活跃序列
服务 | span_name | span_kind | status_code | 指标值 |
---|---|---|---|---|
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 120 |
然而,现在让我们假设它确实会循环,并且偶尔会出现错误。
现在,当代码循环时,Span 有两种潜在结果:一种是所有内容成功完成,另一种是出现错误。这意味着 Span 完成时,status_code
现在要么是 STATUS_CODE_OK
,要么是 STATUS_CODE_ERROR
。因此,标签值可以是指标上的两个值之一,并且我们现在根据 status_code
生成两个活跃序列,一个对应 OK
状态,一个对应错误状态。
同样,我们可以循环一次、10 次、100 次或更多次,但始终只会产生两个活跃序列。
如果现在查看 traces_spanmetrics_call_total
的 Prometheus 即时值,我们会看到下表
服务 | span_name | span_kind | status_code | 指标值 |
---|---|---|---|---|
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 96 |
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_ERROR | 24 |
但是,如果您调用另一个服务会发生什么?让我们添加一个选项,根据某些任意数据,有时我们会下游调用另一个服务,否则则继续在自己的服务中运行循环
在这种情况下,span1
的 span_kind
标签现在要么是 SPAN_KIND_INTERNAL
,要么是 SPAN_KIND_CLIENT
(因为它充当了调用下游服务器的客户端)。如果对下游服务的调用也可能失败,则对于 SPAN_KIND_CLIENT
,status_code
可以是 STATUS_CODE_ERROR
或 STATUS_CODE_OK
。
此时,traces_spanmetrics_call_total
将有四种不同的标签变化
服务 | span_name | span_kind | status_code | 指标值 |
---|---|---|---|---|
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 34 |
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_ERROR | 6 |
Service 1 | span1 | SPAN_KIND_CLIENT | STATUS_CODE_OK | 23 |
Service 1 | span1 | SPAN_KIND_CLIENT | STATUS_CODE_ERROR | 3 |
由于值的变化,我们的指标现在有四个活跃序列,而不是一个。但是,就 Service 1 而言,仍然只有四个活跃序列,因为标签的值没有其他变化。您可以运行 1 个分布式追踪、10 个分布式追踪、100 个分布式追踪(每个包含任意数量的 Span 循环),并且只会产生四个活跃序列。
实际上,我们在上一个图表中只讲了一半的故事。Service 1 调用了第二个服务 Service 2,它通过添加一个新的 Span span2
来延续分布式追踪。如果在 Service 2 内部有一个循环,其中包含一个由 Service 1 的上游调用生成的 Span,然后还有一些内部驱动的 Span,这些 Span 也可能出错,那么我们最终会在 traces_spanmetrics_call_total
指标中得到以下可能的值
服务 | span_name | span_kind | status_code | 指标值 |
---|---|---|---|---|
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 89 |
Service 1 | span1 | SPAN_KIND_INTERNAL | STATUS_CODE_ERROR | 13 |
Service 1 | span1 | SPAN_KIND_CLIENT | STATUS_CODE_OK | 44 |
Service 1 | span1 | SPAN_KIND_CLIENT | STATUS_CODE_ERROR | 9 |
Service 2 | span2 | SPAN_KIND_SERVER | STATUS_CODE_OK | 30 |
Service 2 | span2 | SPAN_KIND_SERVER | STATUS_CODE_ERROR | 14 |
Service 2 | span2 | SPAN_KIND_INTERNAL | STATUS_CODE_OK | 99 |
Service 2 | span2 | SPAN_KIND_INTERNAL | STATUS_CODE_ERROR | 23 |
此时,我们所有的分布式追踪都将由两个潜在的 Span 名称组成,每个名称都会产生两种不同的 span_kind
类型和两种不同的 status_code
类型。因此,一个指标有八个活跃序列。
每个潜在 Span 条件的值的可变性决定了 Tempo 在摄取分布式追踪的 Span 时产生的活跃序列数量,而不是看到的 Span 的分布式追踪数量。
自定义 Span 属性
活跃序列还有另一个考虑因素:可以从 Span 属性添加到指标上的额外标签键/值对。Tempo 指标生成器允许用户使用任意 Span 属性作为指标的标签对。在考虑生成的活跃序列数量时,您还需要确定转换为标签的 Span 属性可能有多少个值。
例如,如果您将 http.method
Span 属性添加到指标标签对中,则有五个可能的值(因为有五种可能的 REST 方法)
HEAD
GET
POST
PUT
DELETE
如果将此标签对添加到每个 Span 指标中,那么每个指标又会生成 5 个潜在的活跃序列(这很可能是最坏情况,极少数 Span 会调用所有五种 REST 方法)。与上表中 8 个活跃序列不同,我们将有 40 个 (8 * 5) 活跃序列。