追踪概述
- 分布式跟踪允许开发人员在大型面向服务的架构中获得调用流的可视化。它对于理解序列化、并行性和延迟来源非常重要。Envoy 支持与系统范围跟踪相关的三个功能:
- 请求 ID 生成:Envoy 将在需要时生成 UUID 并填充 x-request-id HTTP 标头。应用程序可以转发 x-request-id 标头以进行统一日志记录和跟踪。 可以使用扩展在每个HTTP 连接管理器的基础上配置该行为。
- 客户端跟踪 ID 加入:x-client-trace-id标头可用于将不受信任的请求 ID 加入受信任的内部 x-request-id。
- 外部跟踪服务集成:Envoy 支持可插入的外部跟踪可视化提供程序,分为两个子组:
- 作为 Envoy 代码库一部分的外部跟踪器,例如Zipkin、 Jaeger、 Datadog、SkyWalking和 AWS X-Ray。
- 作为第三方插件提供的外部跟踪器,例如Instana。
启用跟踪
处理请求的 HTTP 连接管理器必须设置跟踪对象。有几种方法可以启动跟踪:
- 由外部客户端通过x-client-trace-id
- 通过x-envoy-force-trace
- 通过random_sampling
路由器过滤器还能够通过start_child_span选项为出口调用创建子Span 。
跟踪上下文传播
- Envoy 提供了报告网格内服务间通信跟踪信息的能力
- Envoy 提供了报告有关网格中服务之间通信的跟踪信息的能力。但是,为了能够关联调用流中各种代理生成的跟踪信息,服务必须在入站和出站请求之间传播特定的跟踪上下文。
- 无论使用哪个跟踪提供程序,服务都应该传播 x-request-id以启用跨被调用服务的日志记录以进行关联。
- 跟踪提供者还需要额外的上下文,以使跨度(逻辑工作单元)之间的父/子关系能够被理解。这可以通过直接在服务本身内使用 LightStep(通过 OpenTracing API)或 Zipkin 跟踪器来实现,从入站请求中提取跟踪上下文并将其注入任何后续出站请求。这种方法还将使服务能够创建额外的跨度,描述在服务内部完成的工作,这在检查端到端跟踪时可能很有用。
- 跟踪上下文也可以被服务手工进行传播:
- 使用 LightStep 跟踪器时,Envoy 依赖服务传播 x-ot-span-context
- 使用 Zipkin 跟踪器时,Envoy 依赖服务来传播 B3 HTTP 标头( x-b3-traceid、 x-b3-spanid、 x-b3-parentspanid、 x-b3-sampled和 x-b3-flags)。x-b3-sampled标 头也可以由外部客户端提供,以启用或禁用特定请求的跟踪。此外,还支持单b3标头传播格式,这是一种压缩程度更高的格式。
- 使用 Datadog 跟踪器时,Envoy 依赖该服务来传播 Datadog 特定的 HTTP 标头( x-datadog-trace-id、 x-datadog-parent-id、 x-datadog-sampling-priority)。
- 使用 SkyWalking 跟踪器时,Envoy 依赖该服务来传播 SkyWalking 特定的 HTTP 标头 ( sw8
- 使用 AWS X-Ray 跟踪器时,Envoy 依赖该服务来传播 X-Ray 特定的 HTTP 标头 ( x-amzn-trace-id
每个跟踪包含哪些数据
- 端到端跟踪由一个或多个跨度组成。跨度表示具有开始时间和持续时间并且可以包含与其关联的元数据的逻辑工作单元。Envoy 生成的每个 span 都包含以下数据:
- 原始服务集群,通过--service-cluster选项设置
- 请求的开始时间和持续时间。
- 始发主机,通过--service-node选项设置
- 通过x-envoy-downstream-service-cluster
- HTTP 请求 URL、方法、协议和用户代理。
- 通过custom_tags设置的其他自定义标签。
- 上游集群名称、可观察性名称和地址。
- HTTP 响应状态码。
- GRPC 响应状态和消息(如果可用)。
- HTTP 状态为 5xx 或 GRPC 状态不是“OK”时的错误标记,表示服务器端错误
- 跟踪系统特定的元数据。
- span还包括一个名称(或操作),默认情况下它被定义为被调用服务的主机。但是,这可以使用路由上的config.route.v3.Decorator进行自定义。该名称也可以使用 x-envoy-decorator-operation标头覆盖。
- Envoy 自动将 span 发送给跟踪收集器。根据跟踪收集器的不同,多个跨度使用通用信息拼接在一起,例如全局唯一的请求 ID x-request-id
Envoy sidecar追踪过程
- 用户在请求中注入跟踪相关的请求ID,Envoy Sidecar接入后发送至本地服务(local service),如下图中的App
- Envoy需要把TraceID发给本地服务
- 还可能会附加其它标头
- 本地服务有可能额外需要调用外部的其它服务,其请求通常由Envoy Sidecar上的Egress Listener代理
- 每个请求都需要其ID,为了保持跟踪,需要复制接收到的TraceID,并附加在请求中,以完成传播
- Egress Listener需要继续向后传播该TraceID
- 本地服务App可能调用了多个外部服务
- 每个被调用的外部服务,都应该在Envoy上存在一个Egress Listener
- 在来回的多次请求后,Envoy将最终结果响应给客户端
- 并发请求场景中的连接跟踪需要App参与
- 若无并发请求,Envoy即可处理这些请求中的连接跟踪
- 但在并发场景下,则必须由App来识别不同的请求,因为Envoy无法透视后端的业务逻辑应用也必须要复制请求中的数据才能实现追踪,
- 但这种复杂的功能通常要借助于专门的跟踪系统及相关的库来完成
配置Envoy的跟踪机制
配置Envoy的跟踪介绍
- 目前,Envoy仅支持HTTP协议的跟踪器;
- 在Envoy配置跟踪机制通常由三部分组成
- 定义分布式跟踪系统相关的集群
- 将使用的Zipkin或Jaeger等分布式跟踪系统定义为Envoy可识别的集群;
- 定义在clusters配置段中,需要静态指定;
- tracing{}配置段;
- Envoy使用的跟踪器的全局设定
- 可由Bootstrap配置在顶级配置段定义
- 在http_connection_manager上启用tracing{}配置段
- 用于定义是否向配置的跟踪系统发送跟踪数据
- 侦听器级别的设定
---
static_resources:
listeners:
- name: ...
address: {...}
filter_chains:
- filters:
- name: envoy.http_connection_manager
stat_prefix: ...
route_config: {...}
tracing: {...} # 向tracing provider发送跟踪数据;
...
...
clusters:
- name: zipkin|jaeger|...
...
tracing: {...} # Envoy使用的跟踪器的全局设定,主要用于配置tracing provider;
http: {...} # HTTP跟踪器;
Envoy跟踪的全局配置
以Zipkin为例(Jaeger兼容)
--
tracing:
http:
name: ...
typed_config: # 类型化配置,支持的类型有envoy.tracers.datadog、envoy.tracers.dynamic_ot、envoy.tracers.lightstep、envoy.tracers.opencensus、envoy.tracers.skywalking、envoy.tracers.xray和envoy.tracers.zipkin
"@type": type.googleapis.com/envoy.config.trace.v3.ZipkinConfig # 以zipkin为例
collector_cluster: ... # 指定承载Zipkin收集器的集群名称,该集群必须在Bootstrap静态集群资源中定义;
collector_endpoint: ... # Zipkin服务的用于接收Span数据的API端点;Zipkin的标准配置,其API端点为/api/v2/spans;
trace_id_128bit: ... # 是否创建128位的跟踪ID,默认为false,即使用64位的ID;
shared_span_context: ... # 客户端和服务器Span是否共享相同的span id,默认为true;
collector_endpoint_version: ... # Collocter端点的版本;
collector_hostname: ... # 向collector cluster发送span时使用的主机名,可选;默认为collector_cluster字段中定义的主机名;
在http_connection_manager中发送跟踪数据
---
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
...
generate_request_id: {...} # 连接管理器是否会生成x-request-id标头。默认为true。生成随机UUID4的成本很高,因此在不需要此功能的高吞吐量场景中,可以禁用它。
tracing:
client_sampling: {...} # 由客户端通过x-client-trace-id标头指定进行跟踪时的采样,默认为100%
random_sampling: {...} # 随机抽样,默认100%
overall_sampling: {...} # 整体抽样,默认100%
verbose: ... # 是否为span标注额外信息,设定为true时,则span将包含stream事件的日志信息;
max_path_tag_length: {...} # 记录HTTP URL时使用的最大长度
custom_tags: [] # 自定义标签列表,各标签用于活动的span之上,且名称要惟一;
provider: {...} # 指定要使用的外部tracing provider
name: ... # 要实例化的 HTTP 跟踪驱动程序的名称。
typed_config: {...}
route_config:
...
virtual_hosts:
...
routes:
...
decorator: # 匹配路由的装饰器
operation: ... # 与此路由匹配的请求关联的操作名称。如果启用了跟踪,则此信息将用作为此请求报告的span名称。对于入口(入站)请求或出口(出站)响应,此值可能会被x-envoy-decorator-operation标头覆盖。
propagate: {...} # 装饰的细节是否应该传播给另一方。默认值为true。
response_headers_to_add: # 指定应该添加到此虚拟主机处理的每个响应的 HTTP 标头列表
- header:
key: "x-b3-traceid" # 以zipkin为例
value: "%REQ(x-b3-traceid)%"
- header:
key: "x-request-id"
value: "%REQ(x-request-id)%"
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
start_child_span: ... # 是否为出口路由呼叫启动子span。这在其他过滤器(auth、ratelimit 等)进行出站调用并且子 span 植根于同一个入口父级的情况下很有用。默认为false。
typed_config
参考文档
https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/observability/tracing