WEBKT

实战指南:通过 EnvoyFilter 将自定义 Header 注入 SkyWalking 链路标签

4 0 0 0

在微服务治理中,分布式链路追踪(Distributed Tracing)是定位性能瓶颈和排查调用故障的核心手段。通过 Istio + SkyWalking 的组合,我们往往能轻松获得服务间的拓扑关系和耗时数据。

但在实际业务场景中,仅有“接口路径”和“耗时”是不够的。我们经常需要:

  • 根据 UserID 追踪特定用户的请求路径。
  • 根据 TenantID 分析多租户环境下的资源开销。
  • 根据 Version 区分灰度环境的流量流向。

这些信息通常存在于业务 HTTP Header 中。默认情况下,SkyWalking 的 Envoy 采样器不会记录这些自定义 Header。本文将手把手教你如何编写 EnvoyFilter,在不侵入业务代码的情况下,将这些 Header 转化为 SkyWalking Trace 中的 Tags。


1. 核心原理

在 Istio 中,Envoy 作为 Sidecar 拦截所有进出流量。SkyWalking 的链路数据由 Envoy 的 tracing 模块生成。

Envoy 的 HttpConnectionManager (HCM) 允许配置 custom_tags。通过这个配置,我们可以告诉 Envoy:“请从 HTTP Header 中提取名为 X-Business-ID 的值,并将其作为名为 biz.id 的标签放入当前 Span 中。”

由于 Istio 默认的配置中没有这一项,我们需要使用 EnvoyFilter 资源,以补丁(Patch)的形式将这段配置注入到指定服务的 Envoy 代理中。


2. 编写 EnvoyFilter

假设我们要提取的 Header 名称为 x-client-id,希望在 SkyWalking 显示的标签名为 client.id

创建一个名为 inject-skywalking-tag.yaml 的文件:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: skywalking-custom-tags
  namespace: istio-system # 如果希望全局生效,放在 istio-system;否则放在业务命名空间
spec:
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND # 作用于流入流量
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
      patch:
        operation: MERGE
        value:
          typed_config:
            "@type": "type.googleapis.com/envoy.extensions.filters.http.connection_manager.v3.HttpConnectionManager"
            tracing:
              custom_tags:
                - name: client.id  # 在 SkyWalking 中显示的 Tag 名称
                  request_header:
                    name: x-client-id # 要提取的 HTTP Header 名称
                    default_value: "unknown" # 如果没有该 Header 时的默认值
                - name: region
                  request_header:
                    name: x-region-id
                    default_value: "default-region"

3. 关键字段解析

  • context: SIDECAR_INBOUND:
    • SIDECAR_INBOUND: 当请求到达目标服务时记录。通常建议在这里记录,因为这能确保标签绑定在服务接收端的根 Span 上。
    • GATEWAY: 如果你希望在 Istio Ingress Gateway 就开始记录,需要将 context 改为 GATEWAY。
  • operation: MERGE: 使用合并操作。Envoy 会保留现有的 tracing 配置,并将我们的 custom_tags 插入其中。
  • custom_tags 类型:
    • request_header: 最常用的类型,从 HTTP Header 提取。
    • literal: 静态字符串,用于区分集群或环境。
    • environment: 从环境变量中提取。

4. 部署与验证

第一步:应用配置

执行命令:

kubectl apply -f inject-skywalking-tag.yaml

第二步:触发流量

调用你的业务接口,并带上自定义 Header:

curl -H "x-client-id: user-12345" http://your-service-api/path

第三步:在 SkyWalking UI 查看

  1. 打开 SkyWalking 仪表盘。
  2. 进入 Trace 视图。
  3. 找到对应的请求 Span。
  4. 点击 Span 详情,在 Tags 标签页下,你应该能看到:
    • client.id: user-12345

5. 进阶:如何确保全链路透传?

需要注意,EnvoyFilter 只能保证当前服务记录了这个 Tag。如果你希望这个 Header 在整个调用链(服务 A -> 服务 B -> 服务 C)中都能在每个 Span 上被记录,你需要确保:

  1. 业务代码透传:服务 A 在调用服务 B 时,必须将接收到的 x-client-id 手动传递给下游。Envoy 不会自动跨服务传播非标准的自定义 Header(除非你在 Envoy 中配置了 Header 传播,或者使用 SkyWalking 的 SDK 进行了透传)。
  2. 全局 EnvoyFilter:将上述 EnvoyFilter 部署在 istio-system 命名空间,并省略特定的 workloadSelector,使其对网格内所有 Sidecar 生效。

6. 注意事项与性能

  • 性能消耗:提取 Header 并添加 Tag 对 Envoy 性能损耗极低,几乎可以忽略不计。但请避免在 Tag 中存储超大的 Value(如整个 JSON Body),这会导致 Trace 数据包过大,增加存储压力。
  • 配置冲突:如果你已经使用了 Telemetry API 配置 Tracing,请谨慎使用 EnvoyFilter 手动 Patch,因为这可能导致配置覆盖冲突。在 Istio 1.15+ 版本中,建议优先查看 Telemetry API 是否能满足需求。
  • Header 匹配:Envoy 默认使用小写 Header 名称。虽然 Envoy 会自动处理大小写,但建议在 YAML 配置中使用小写形式以保持一致。

通过这种方式,我们可以极大地增强链路追踪的业务属性,让运维和开发人员在海量的调用数据中,精准地通过业务维度进行定位和分析。

云原生实战派 IstioSkyWalking

评论点评