Istio Trace链路追踪方案

7,102 阅读9分钟

[TOC]

Istio Trace链路追踪方案

Istio Trace支持

envoy支持trace

envoy原生就支持分布式追踪系统的接入,如支持jaeger和zipkin,如envoy的Tracing官方文档中表明envoy支持如下trace特性:

  • 生成Request Id,填充HTTP的header字段x-request-id
  • 外部跟踪服务集成,如支持LightStep, Zipkin或任何Zipkin兼容后端(如Jaeger)
  • 添加Client trace ID

相关信息可以参考这里 或者 envoy官方文档Jaeger Tracing,另外,在源码中有对应的trace相关的源码

Istio支持trace

Istio的分布式追踪相关介绍里面相关说明可以知道,Istio的envoy代理拦截流量后会主动上报trace系统,通过proxy的参数zipkinAddress指定了trace系统的地址,这样就不会再经过mixer了,直接envoy和trace系统交互,大体流程:

  • 如果incoming的请求没有trace相关的headers,则会再流量进入pods之前创建一个root span

  • 如果incoming的请求包含有trace相关的headers,Sidecar的proxy将会extract这些span的上下文信息,然后再在流量进入pods之前创建一个继承上一个span的新的span

由于Istio的proxy代理是envoy,而envoy又原生支持jaeger,那因此Istio自然而然就支持jaeger了,在官方文档Distributed Tracing中有相关较为详细的说明

当然,默认是通过envoy这个proxy直接上报的,如果要经过mixer上报,也是可行的,可以进行相关配置,额外处理一下,具体可以参考idou老师教你学Istio 08: 调用链埋点是否真的“零修改”?

不过目前envoy支持的trace方案相对比较简单,采用策略无法应用于Jaeger的所有策略,然后也不支持不同业务有不同的采样策略,因此Istio进行配置,也是全局的。

~/goDev/Applications/src/Istio.io/Istio/pilot/pkg/networking/core/v1alpha3/listener.go中的源码如下:

	if env.Mesh.EnableTracing {
		tc := model.GetTraceConfig()
		connectionManager.Tracing = &http_conn.HttpConnectionManager_Tracing{
			OperationName: httpOpts.direction,
			ClientSampling: &envoy_type.Percent{
				Value: tc.ClientSampling,
			},
			RandomSampling: &envoy_type.Percent{
				Value: tc.RandomSampling,
			},
			OverallSampling: &envoy_type.Percent{
				Value: tc.OverallSampling,
			},
		}
		connectionManager.GenerateRequestId = &google_protobuf.BoolValue{Value: true}
	}

Trace(jaeger)的持久化存储

jaeger在Istio中的现状

更多jaegertracing信息查看官网架构介绍

jaeger的简单部署

目前官方自带的jaeger采用的是jaegertracing/all-in-one这个镜像,这个会包含三个组件 jaeger-agent、jaeger-collector、jaeger-query,其中jaeger-collector会将数据存储,而all-in-one这镜像目前仅仅是存储在内存里面的,也就是临时存储,如果删掉pod重启,jaeger的数据是没有了的。 jaegertracing/all-in-one镜像内存存储相关

为此,我们要考虑,如何将jaeger-collector的数据存储指定为自己的存储服务如ES集群,采用官方自带的肯定不行了,只能是自己部署一套jaeger服务,或者让jaeger服务的agent的收集地址指向我们自己的服务

doc.Istio.cn/en/help/faq… Istio.io/docs/refere…

这两篇文章有说设置trace_zipkin_url, trace_jaeger_url,可以达到目的,查看yaml配置发现mixer只有设置trace_zipkin_url:

      containers:
      - name: mixer
        image: "docker.io/Istio/mixer:1.0.0"
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9093
        - containerPort: 42422
        args:
          - --address
          - unix:///sock/mixer.socket
          - --configStoreURL=k8s://
          - --configDefaultNamespace=Istio-system
          - --trace_zipkin_url=http://zipkin:9411/api/v1/spans

这个只是针对Mixer组件而言的trace,如果是envoy本身的tarce,需要修改proxyv2的参数

jaeger持久化存储的方案

Istio开源版本中,调用链对接jaeger是从envoy直接报上去的,没有通过mixer来做。

因为调用链的数据量会很大,可靠性以及规模确是需要重点考虑的,因此必须要使用自己的服务 ,如果要配置为自己的jaeger服务,需要用kubectl修改Istio这个configmap中的zipkinAddress,配置为自己的服务地址,另外就是jaeger收数据是兼容zipkin的。

kubectl get configmap Istio -n Istio-system  -o yaml |grep zipkinAddress

有两处zipkinAddress地址,如下:
zipkin.Istio-system:9411

对于华为云而言,调用链这里他们会对接到华为云的apm服务,在可靠性和性能上都会有保证。

对接外部的trace系统[Jaeger]

K8S独立部署Jaeger组件

根据K8S安装部署Jaeger官方文档部署基于k8s的Jaeger的生产环境下的容器,注意一定要采用文档中Production这个生成的部署方式。

注意创建Elasticserach的时候,需要等待特别久,而且一定要等到Elasticserach这个pod的状态为Running的时候才能创建Jaeger的其他组件,因为其他组件要依赖Elasticserach

然后修改jaeger-query这个Service的type为NodePort,然后通过 kubectl get service jaeger-query ,可以看到Port,然后利用host ip可以访问,如2.2集群独立部署的Jaeger Query UI

需要部署jaeger相对比较麻烦,有一些参数需要设置,这个需要一定的学习能力,需要对jaeger对外暴露的端口、协议有一定的理解;然后还需要对存储引擎如ES有一定的了解

另外,如果是通过二进制安装部署的话,相对较为简单,只需要注意启动参数即可

修改Istio到已有Jaeger服务

通过kubectl get configmap istio -n istio-system -o yaml |grep zipkinAddress先直接修改zipkinAddress的地址,指定为jaeger-collector这个Service的地址,端口是9411,只有这个9411地址才兼容zipkin协议。因为envoy这个proxy会默认使用环境变量来设置zipkinAddress地址,默认地址是zipkin.istio-system:9411。修改过configmap之后,如果后面通过helm upgrade更新,则现在通过这个方式来修改的数据会失效,因此要完全修改,则必须通过修改过install/kubernetes/helm/istio//templates/configmap.yaml,同时还要修改install/kubernetes/helm/istio//charts/mixer/templates下面的zipkin相关的地址。

如果是istio.yaml这个模板文件部署,则还需:

  • 修改istio.yaml文件中的 zipkinAddress: zipkin.Istio-system:9411

    • 修改为:zipkinAddress: 10.233.61.200:9411【ClusterIP只针对K8S集群内】
  • 修改istio.yaml文件中的mixer相关的trace_zipkin_url地址

    • 修改为:--trace_zipkin_url=http://10.233.61.200:9411/api/v1/spans【ClusterIP只针对K8S集群内】
  • 修改istio.yaml文件中的proxyv2相关的zipkinAddress这个args

    • 修改为:10.233.61.200:9411【ClusterIP只针对K8S集群内】

其他说明:

  • 修改所有zipkinAddress相关的地址为jaeger-collector这个Service的地址,这个如果都是K8S集群,可以直接配置为ClusterIP,但是实际中需要配置一个全局域名

    • istio这个configmap中的zipkinAddress地址,proxy会采用这个环境变量,但是已经部署的pod不会生效了,因为是手动注入的,istioctl kube-inject的时候才会用到proxy的环境变量,因此需要删除Deployment然后重新部署生效。如果是自动注入的应该就只需要重启pod。
  • jaeger-agent这个服务,如果Istio直接配置为外部jaeger地址的话,是不会经过jaeger-agent的,因此可以关闭

  • 由于通过ES进行数据存储,因此现在杀掉jaeger相关的Pod,重启后数据依然存在

  • 对接到外部jaeger服务的话,Istio自带的jaeger相关的就可以直接关闭了

采样策略修改和配置

Jaeger本身支持在client端调整和通过collector调整采样策略,但是在Istio中并没有Jaeger的client,只是envoy里面支持了trace,直接修改envoy的trace相关源码不太友好。不过Istio中提供了一个全局的设置,通过设置pilot的参数可以用来控制采用策略。

Istio的采样流程大致是:在pilot的v1alpha3的流量管理接口中,在提供Listener的Http filters的时候会判断:是否使能了mesh的trace,如果使能,则创建trace并读取 采用配置,采样通过环境变量PILOT_TRACE_SAMPLING来配置,其范围是0.0 - 100.0,默认为100,全采样。

修改的方式有两种:

  • helm安装时候的选项参数:pilot.traceSampling

  • 通过kubectl -n Istio-system edit deploy Istio-pilot修改PILOT_TRACE_SAMPLING变量

具体详见

PILOT_TRACE_SAMPLING的值是100的时候,表示全采样,每一次请求都会采样,可以验证得到,通过访问测试页面,记录发起的请求次数,然后查看Jaeger Trace UI,查看Services为productpage的Trace,发现发起请求的次数和Trace的次数保持一致。

PILOT_TRACE_SAMPLING的值是50的时候,表示采样1/2,每两次请求都会采样一次,修改完后,等待一小会儿,然后验证。验证结果表示现在并非1:2,但是也不完全是1/2的概率,具体还有待分析Jaeger的原理,但是至少证明了策略的修改是有效的

对接Mtrace系统

现有Mtrace系统,在原有Jaeger基础上做了一些调整,使用了protobuf协议,同时增加了kafka。因此要想对接MTrace系统,还需要对proxy(envoy)做一些调整,并不是仅仅修改一些配置参数和地址等就可以解决的

业务接入Trace链路注意点

a,业务处理HTTP Header

虽然Istio能够拦截流量并自动发送Span信息,但是要把整个过程统一追踪并链接起来,还需要业务在代码中处理和追踪相关的HTTP Header,这样代理在发送 Span 信息的时候,才能正确的把同一个跟踪过程统一起来。具体详见

在Mtrace等系统或者原生的jaeger中,会有有个client的角色存在,这个client会创建并初始化一个trace,并处理好TraceID的事情,但是Istio后,服务中没有Mtrace 发client端的 SDK,因此才需要再业务代码中处理好http header,但是对于非HTTP如TCP需要自行扩展支持,这个暂时不考虑;对应gRPC的话,因为也是基于http,因此可以通过一些方式添加。

所以,对于trace这块,并非完全没有任何侵入,业务代码有一点点小的改动,就是需要额外处理下http 的指定的header并依次传递

b,Istio设置采样百分比

百分比默认值为100,全部采样,可以修改为0-100;修改的方式有两种:

  • helm安装时候的选项参数:pilot.traceSampling

  • 通过kubectl -n Istio-system edit deploy Istio-pilot修改PILOT_TRACE_SAMPLING变量

具体详见

这个设置是全局的,没有办法针对特定业务有特定的采样策略。如果需要对特定业务采样,就需要给collector配置静态的json策略文件,然后也需要client支持,具体可以参考Jaeger官方文档。

问题 & TODO

  1. 需要业务代码中处理好http header,但是对于非HTTP而言,怎么弄 ?

    • http 和 gRPC都需要业务自己处理好header
    • TCP需要自定义扩展字段
  2. 不通过envoy上报,通过mixer上报

  3. 支持不同业务不同的采用策略

参考

Istio 分布式追踪文档

jaeger-kubernetes生产部署

idou老师教你学Istio 08: 调用链埋点是否真的“零修改”?

【"欢迎关注我的微信公众号:Linux 服务端系统研发,后面会大力通过微信公众号发送优质文章"】

我的微信公众号