菜单
开源

基于尾部的采样

注意

Grafana Alloy 是我们 OpenTelemetry Collector 分发版的新名称。Grafana Agent 已被废弃,并将进入长期支持 (LTS),直到 2025 年 10 月 31 日。Grafana Agent 将于 2025 年 11 月 1 日达到生命周期结束 (EOL)。请阅读更多关于我们为什么建议迁移到 Grafana Alloy 的信息。

Tempo 旨在提供一种廉价的解决方案,使 100% 采样成为可能。然而,有时由于运行时或出口流量相关成本等限制,较低的采样率是必要或合意的。概率采样策略易于实现,但也有丢失您以后想要的相关数据的风险。

基于尾部的采样适用于 Grafana Agent 的 Flow 或 static 模式。Flow 模式配置文件使用 River 编写。Static 模式配置文件使用 YAML 编写。本文档中的示例适用于 Flow 模式。您也可以使用Static 模式 Kubernetes operator

基于尾部的采样工作原理

在基于尾部的采样中,采样决策在工作流程的末尾做出,从而实现更准确的采样决策。Grafana Agent 按跟踪 ID 对 spans 进行分组,并检查其数据,以确定是否满足定义的策略之一(例如,latencystatus_code)。例如,策略可以检查跟踪是否包含错误或是否花费的时间超过某个特定时长。

如果跟踪满足至少一个策略,则对其进行采样。

为了按跟踪 ID 对 spans 进行分组,Agent 会缓冲 spans 可配置的时长,之后它认为跟踪已完成。长时间运行的跟踪会被分割成多个。然而,等待更长时间会增加缓冲的内存开销。

对跟踪数据进行分组的一个特殊挑战在于多实例 Agent 部署,其中属于同一跟踪的 spans 可能会到达不同的 Agent。为了解决这个问题,您可以配置 Agent 通过将属于同一跟踪的 spans 导出到同一实例来在 Agent 实例之间进行负载均衡跟踪。这通过在 spans 从应用到达后按跟踪 ID 重新分发来实现。Agent 必须能够发现并连接到可能接收同一跟踪 spans 的其他 Agent 实例。Kubernetes 用户应使用无头服务(headless service)

这是通过在接收到应用程序发送的跨度后,根据跟踪 ID 重新分发跨度来实现的。Agent 必须能够发现并连接到其他 Agent 实例,这些实例可能会接收到同一跟踪的跨度。Kubernetes 用户应该使用一个无头服务

按跟踪 ID 重新分发 spans 意味着 spans 会被发送和接收两次,这可能导致 CPU 使用率显著增加。这种开销随着共享同一跟踪的 Agent 实例数量增加而增加。

Tail-based sampling overview

快速入门

要开始使用基于尾部的采样,请定义采样策略。如果您使用的是多实例 Agent 部署,请添加负载均衡并指定解析机制以查找设置中的其他 Agent。要查看所有可用的配置选项,请参阅配置参考

注意

Grafana Alloy 提供了将您的 Agent Static 或 Flow 配置文件转换为可被 Alloy 使用的格式的工具。

有关更多信息,请参阅迁移到 Alloy

Grafana Agent Flow 示例

Grafana Agent Flow 是 Grafana Agent 基于组件的修订版,专注于易用性、可调试性以及适应高级用户需求的能力。Flow 配置文件使用 River 而非 YAML 编写。

Grafana Agent Flow 使用 otelcol.processor.tail_sampling component` 进行基于尾部的采样。

river
otelcol.receiver.otlp "otlp_receiver" {
    grpc {
        endpoint = "0.0.0.0:4317"
    }

    output {
        traces = [
            otelcol.processor.tail_sampling.policies.input,
        ]
    }
}

otelcol.exporter.otlp "tempo" {
    client {
        endpoint = "tempo:4317"
    }
}

// The Tail Sampling processor will use a set of policies to determine which received
// traces to keep and send to Tempo.
otelcol.processor.tail_sampling "policies" {
    // Total wait time from the start of a trace before making a sampling decision.
    // Note that smaller time periods can potentially cause a decision to be made
    // before the end of a trace has occurred.
    decision_wait = "30s"

    // The following policies follow a logical OR pattern, meaning that if any of the
    // policies match, the trace will be kept. For logical AND, you can use the `and`
    // policy. Every span of a trace is examined by each policy in turn. A match will
    // cause a short-circuit.

    // This policy defines that traces that contain errors should be kept.
    policy {
        // The name of the policy can be used for logging purposes.
        name = "sample-erroring-traces"
        // The type must match the type of policy to be used, in this case examining
        // the status code of every span in the trace.
        type = "status_code"
        // This block determines the error codes that should match in order to keep
        // the trace, in this case the OpenTelemetry 'ERROR' code.
        status_code {
            status_codes = [ "ERROR" ]
        }
    }

    // This policy defines that only traces that are longer than 200ms in total
    // should be kept.
    policy {
        // The name of the policy can be used for logging purposes.
        name = "sample-long-traces"
        // The type must match the policy to be used, in this case the total latency
        // of the trace.
        type = "latency"
        // This block determines the total length of the trace in milliseconds.
        latency {
            threshold_ms = 200
        }
    }

    // The output block forwards the kept traces onto the batch processor, which
    // will marshall them for exporting to Tempo.
    output {
        traces = [otelcol.exporter.otlp.tempo.input]
    }
}

Grafana Agent static 模式示例

更多信息,请参阅博文使用 Grafana Tempo 和 Grafana Agent 进行跟踪采样简介

状态码基于尾部的采样策略

以下策略仅对至少一个 span 包含 OpenTelemetry 错误状态码的跟踪进行采样。

yaml
traces:
  configs:
    - name: default
    ...
    tail_sampling:
      policies:
        - type: status_code
          status_code:
            status_codes:
              - ERROR

Span 属性基于尾部的采样策略

以下策略仅对 span 属性 http.target *不*包含值 /healthcheck 或以 /metrics/ 开头的跟踪进行采样。

yaml
traces:
   configs:
   - name: default
    tail_sampling:
      policies:
        - type: string_attribute
          string_attribute:
            key: http.target
            values:
              - ^\/(?:metrics\/.*|healthcheck)$
            enabled_regex_matching: true
            invert_match: true

以及复合基于尾部的采样策略

以下策略仅在子策略的所有条件都满足时对跟踪进行采样。在本例中,它结合了前面两个策略,并且仅对 span 属性 http.target *不*包含值 /healthcheck 或以 /metrics/ 开头 *并且* 跟踪中至少有一个 span 包含 OpenTelemetry 错误状态码的跟踪进行采样。

yaml
traces:
   configs:
   - name: default
    tail_sampling:
      policies:
       - type: and
            and_sub_policy:
            - name: and_tag_policy
              type: string_attribute
              string_attribute:
                key: http.target
                values:
                    - ^\/(?:metrics\/.*|healthcheck)$
                enabled_regex_matching: true
                invert_match: true
            - name: and_error_policy
              type: status_code
              status_code:
                status_codes:
                  - ERROR