[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
-
需要业务代码中处理好http header,但是对于非HTTP而言,怎么弄 ?
- http 和 gRPC都需要业务自己处理好header
- TCP需要自定义扩展字段
-
不通过envoy上报,通过mixer上报
-
支持不同业务不同的采用策略
参考
Istio 分布式追踪文档
jaeger-kubernetes生产部署
idou老师教你学Istio 08: 调用链埋点是否真的“零修改”?