Istio 分布式追踪

Istio网格中的分布式跟踪

  • 分布式跟踪的基础概念

    • Span是跟踪中的原子单元

    • 为了能够正确地创建及重组跟踪,需要完成三个任务

      • Incoming request spans:当某个请求进入服务时,需要检查它是否具有跟踪标头;不存在时则需要创建一个root span,否则需要创建一个child span以继续跟踪;
      • Outgoing request spans:当某个请求从一个服务发送到另一个不同的服务时,可以先创建一个span,然后接收服务可以继续前一步中描述的跟踪;
      • Context propagation:上下文传播

        • 服务通常同时接收和发送多个请求,因此,需要借助应用的介入才能分辨传入和传出的请求之间的连接,此即为需要实现上下文传播之处
        • 对于HTTP,可以让Envoy Sidecar通过将跟踪标头从传入调用传播到应用程序内部的传出调用来构建完整的跟踪过程
  • Istio网络中的分布式跟踪由Envoy Sidecar代理完成,对应用代码是“近零侵入”

    • 在启用了Sidecar Injection的Istio网络中,所有传入及付出服务的请求首先要通过本地的Envoy Sidecar进行代理

    • Envoy Sidecar负责创建root span和child span,它们是请求跟踪所需要的三个任务中的两个

    • context propagation需要通过应用程序的内部逻辑(简单打点)来完成

Envoy的分布式跟踪机制

  • Envoy用三个功能来支撑系统范围内的跟踪:

    • 生成请求ID:Envoy 会在需要的时候生成UUID,并填充x-request-id HTTP标头,应用可以转发这个标头以进行统一的记录和跟踪;
    • 集成外部跟踪服务:Envoy支持可插接的外部跟踪可视化服务,包括LightStep、Zipkin 或者 Zipkin 兼容的后端(例如 Jaeger);
    • 加入客户端跟踪ID:x-client-trace-id标头可以用来把不受信的请求ID连接到受信的x-request-id标头;
  • 处理请求的HTTP连接管理器必须设置跟踪对象,有多种途径可以初始化跟踪:
    • 外部客户端,使用x-client-trace-id

    • 内部服务,使用x-envoy-force-trace

    • 随机采样使用运行时设置random_sampling

  • 路由过滤器可以使用start_child_span来为egress调用创建子Span;

传播上下文信息

  • Envoy 提供了向跟踪系统报告网格内服务间通信相关跟踪信息的能力
    • 为了能够关联由请求流程中的各种代理生成的跟踪信息,服务必须在入站和出站请求之间传播某些跟踪上下文
    • 无论使用哪个跟踪服务,都应该传播x-request-id,这样在被调用服务中启动相关性的记录

  • 跟踪上下文也依赖于被代理的应用传播相应跟踪器特有的标头

    • Zipkin跟踪器:Envoy依赖于服务来传播B3特有的HTTP标头(x-b3-traceid, x-b3-spanid, x-b3-parentspanid,x-b3-sampled和 x-b3-flags)
    • Datadog跟踪器:Envoy依赖于服务传播Datadog特有的HTTP标头( x-datadog-trace-id, x-datadog-parent-id, x-datadog-sampling-priority)
    • LightStep跟踪器:Envoy依赖于服务传播LightStep特有的HTTP标头(x-ot-span-context)
    • Skywalking跟踪器: Envoy依赖于服务传播SkyWalking特有的HTTP标头(sw8)
    • AWS X-Ray跟踪器:Envoy依赖于服务传播X-Ray特有的HTTP标头(x-amzn-trace-id)
    • 此外,基于OpenCensus(例如Stackdriver)的跟踪器也需要传播其特有HTTP标头(x-cloud-trace-context、traceparent和grpc-trace-bin)

Envoy跟踪中的数据

  • Envoy生成的每个Span包含以下数据

    • 原始服务集群,通过--service-cluster选项设置
    • 请求的开始时间和持续时间;
    • 始发主机,通过--service-node选项设置
    • 通过x-envoy-downstream-service-cluster 标头设置下游集群;
    • HTTP URL;
    • HTTP方法;
    • HTTP响应码;
    • 跟踪系统特定的元数据;
  • 这些数据将记录于跟踪系统的存储之中

全局配置跟踪功能

  • 部署网格时,通过IstioOperator配置中的MeshConfig段进行全局配置

  • 部署网格后,通过IstioOperator配置中的MeshConfig段进行全局配置

tracing.yaml

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
  meshConfig:
    enableTracing: true    # 启用tracing机制
    defaultConfig:
      tracing:
        sampling: 100.0    # 采样率,取值范围为(0.0-100.0)
        max_path_tag_length: 256   # 路径标签最大长度
        custom_tags:
          clusterID:       # 添加一个名为 clusterID 的标记
          environment:
            name: ISTIO_META_CLUSTER_ID   # 使用 ISTIO_META_CLUSTER_ID 环境变量注入到pod

应用资源

# istioctl install -f ./tracing.yaml

工作负载级配置跟踪功能

  •  在工作负载的podTemplate资源上,通过“proxy.istio.io/config”注解进行配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  ...
  template:
    metadata:
      ...
      annotations:
        ...
        proxy.istio.io/config: |
          tracing:
            sampling: 10
            custom_tags:
              my_tag_header:
                header:
                  name: host
    spec:
      ...

Telemetry CR资源定义追踪功能

在root namespace中启用网格全局追踪

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system
spec:
  # no selector specified, applies to all workloads
  tracing:
  - randomSamplingPercentage: 10.00
    providers:
    - name: localtrace
    customTags:
      foo:
        literal:
          value: bar

namespace级别配置

apiVersion: telemetry.istio.io/v1alpha1 
kind: Telemetry
metadata:
  name: namespace-override
  namespace: default
spec:
  tracing:
  - customTags: 
      userId:
        header:
          name: userId 
          defaultValue: unknown

工作负载级别配置

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: foo-tracing
  namespace: bar
spec:
  selector:
    matchLabels:
      service.istio.io/canonical-name: foo
  tracing:
  - disableSpanReporting: true

追踪示例

def getForwardHeaders(request):
    headers = {}

    # x-b3-*** headers can be populated using the opentracing span
    span = get_current_span()
    carrier = {}
    tracer.inject(
        span_context=span.context,
        format=Format.HTTP_HEADERS,
        carrier=carrier)

    headers.update(carrier)

    # ...

        incoming_headers = ['x-request-id',
        'x-ot-span-context',
        'x-datadog-trace-id',
        'x-datadog-parent-id',
        'x-datadog-sampling-priority',
        'traceparent',
        'tracestate',
        'x-cloud-trace-context',
        'grpc-trace-bin',
        'user-agent',
        'cookie',
        'authorization',
        'jwt',
        'sw8',                    
    ]

    # ...

    for ihdr in incoming_headers:
        val = request.headers.get(ihdr)
        if val is not None:
            headers[ihdr] = val

    return headers

参考文档

https://istio.io/latest/zh/docs/tasks/observability/distributed-tracing/

https://istio.io/latest/zh/docs/reference/config/telemetry/

posted @ 2022-12-01 18:33  小吉猫  阅读(179)  评论(0编辑  收藏  举报