在云原生应用中,一次请求往往需要经过一系列的 API 或后台服务处理才能完成,这些服务有些是并行的,有些是串行的,而且位于不同的平台或节点。那么如何确定一次调用的经过的服务路径和节点以帮助我们进行问题排查?这时候就需要使用到分布式追踪。
本文将向你介绍:
分布式追踪的原理
如何选择分布式追踪软件
在 Istio 中如何使用分布式追踪
以 Bookinfo 和 SkyWalking 为例说明如何查看分布式追踪数据
分布式追踪基础
分布式追踪是一种用来跟踪分布式系统中请求的方法,它可以帮助用户更好地理解、控制和优化分布式系统。分布式追踪中用到了两个概念:TraceID 和 SpanID。
TraceID 是一个全局唯一的 ID,用来标识一个请求的追踪信息。一个请求的所有追踪信息都属于同一个 TraceID,TraceID 在整个请求的追踪过程中都是不变的;
SpanID 是一个局部唯一的 ID,用来标识一个请求在某一时刻的追踪信息。一个请求在不同的时间段会产生不同的 SpanID,SpanID 用来区分一个请求在不同时间段的追踪信息;
TraceID 和 SpanID 是分布式追踪的基础,它们为分布式系统中请求的追踪提供了一个统一的标识,方便用户查询、管理和分析请求的追踪信息。
下面是分布式追踪的过程:
当一个系统收到请求后,分布式追踪系统会为该请求分配一个 TraceID,用于串联起整个调用链;
分布式追踪系统会为该请求在系统内的每一次服务调用生成一个 SpanID 和 ParentID,用于记录调用的父子关系,没有 ParentID 的 Span 将作为调用链的入口;
每个服务调用过程中都要传递 TraceID 和 SpanID;
在查看分布式追踪时,通过 TraceID 查询某次请求的全过程;
Istio 如何实现分布式追踪
Istio 中的分布式追踪是基于数据平面中的 Envoy 代理实现的。服务请求在被劫持到 Envoy 中后,Envoy 在转发请求时会附加大量 Header,其中与分布式追踪相关的有:
作为 TraceID:x-request-id
用于在 LightStep 追踪系统中建立 Span 的父子关系:x-ot-span-context
用于 Zipkin,同时适用于 Jaeger、SkyWalking,详见 b3-propagation:
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
b3
用于 Datadog:
x-datadog-trace-id
x-datadog-parent-id
x-datadog-sampling-priority
用于 SkyWalking:sw8
用于 AWS X-Ray:x-amzn-trace-id
关于这些 Header 的详细用法请参考 Envoy 文档 。
Envoy 会在 Ingress Gateway 中为你产生用于追踪的 Header,不论你的应用程序使用何种语言开发,Envoy 都会将这些 Header 转发到上游集群。但是,你还要对应用程序代码做一些小的修改,才能为使用分布式追踪功能。这是因为应用程序无法自动传播这些 Header,可以在程序中集成分布式追踪的 Agent,或者在代码中手动传播这些 Header。Envoy 会将追踪数据发送到 tracer 后端处理,然后就可以在 UI 中查看追踪数据了。
例如在 Bookinfo 应用中的 Productpage 服务,如果你查看它的代码可以发现,其中集成了 Jaeger 客户端库,并在 getForwardHeaders (request) 方法中将 Envoy 生成的 Header 同步给对 Details 和 Reviews 服务的 HTTP 请求:
在这里插入代码片
def getForwardHeaders(request):
headers = {}
# 使用 Jaeger agent 获取 x-b3-* header
span = get_current_span()
carrier = {}
tracer.inject(
span_context=span.context,
format=Format.HTTP_HEADERS,
carrier=carrier)
headers.update(carrier)
# 手动处理非 x-b3-* header
if 'user' in session:
headers['end-user'] = session['user']
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',
'sw8',
'user-agent',
'cookie',
'authorization',
'jwt',
]
for ihdr in incoming_headers:
val = request.headers.get(ihdr)
if val is not None:
headers[ihdr] = val
return headers
分布式追踪系统如何选择
分布式追踪系统的原理类似,市面上也有很多这样的系统,例如 Apache SkyWalking 、Jaeger 、Zipkin 、LightStep 、Pinpoint 等。我们将选择其中三个,从多个维度进行对比。之所以选择它们是因为:
它们是当前最流行的开源分布式追踪系统;
都是基于 OpenTracing 规范;
都支持与 Istio 及 Envoy 集成;
实验
参考 Istio 文档 来安装和配置 Apache SkyWalking。
环境说明
以下是我们实验的环境:
Kubernetes 1.24.5
Istio 1.16
SkyWalking 9.1.0
安装 Istio
安装之前可以先检查下环境是否有问题:
$ istioctl experimental precheck
✔ No issues found when checking the cluster. Istio is safe to install or upgrade!
To get started, check out https://istio.io/latest/docs/setup/getting-started/
然后安装 Istio 同时配置发送追踪信息的目的地为 SkyWalking:
# 初始化 Istio Operator
istioctl operator init
# 安装 Istio 并配置使用 SkyWalking
kubectl apply -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
name: istio-with-skywalking
spec:
meshConfig:
defaultProviders:
tracing:
- "skywalking"
enableTracing: true
extensionProviders:
- name: "skywalking"
skywalking:
service: tracing.istio-system.svc.cluster.local
port: 11800
EOF
部署 Apache SkyWalking
Istio 1.16 支持使用 Apache SkyWalking 进行分布式追踪,执行下面的代码安装 SkyWalking:
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/extras/skywalking.yaml
打开 SkyWalking UI:istioctl dashboard skywalking