概述

分布式链路追踪可以让用户对跨多个分布式服务网格的 1 个请求进行追踪分析。 进而可以通过可视化的方式更加深入地了解请求的延迟、序列化和并行度。

Istio 利用 Envoy 的分布式追踪功能提供了开箱即用的链路追踪集成。 确切地说,Istio 提供了安装各种链路追踪后端服务的选项,并且通过配置代理来自动发送链路追踪 span 到分布式追踪系统服务。 请参阅 ZipkinJaegerLightstep 的任务文档来了解 Istio 如何与这些分布式链路追踪系统协作。

追踪上下文传递

尽管 Istio 代理能够自动发送 span,但需要一些附加信息才能将这些 span 加到同一个调用链。 所以当代理发送 span 信息的时候,应用程序需要附加适当的 HTTP 请求头信息,这样才能够把多个 span 加到同一个调用链。

要做到这一点,每个应用程序必须从每个传入的请求中收集请求头,并将这些请求头转发到传入请求所触发的所有传出请求中。 具体选择转发哪些请求头取决于所配置的链路追踪后端,要转发的请求头在每个链路追踪系统特定的任务页面进行说明, 以下是一个汇总:

所有应用程序必须转发以下请求头:

  • x-request-id:这是 Envoy 专用的请求头,用于对日志和追踪进行一致的采样。

对于 Zipkin、Jaeger 和 Stackdriver,应转发 B3 多请求头格式:

  • x-b3-traceid
  • x-b3-spanid
  • x-b3-parentspanid
  • x-b3-sampled
  • x-b3-flags

这些是 Zipkin、Jaeger 和其它更多工具支持的请求头。

对于 Datadog,应转发以下请求头,这些转发由对应语言和框架的 Datadog 客户端库自动处理。

  • x-datadog-trace-id
  • x-datadog-parent-id
  • x-datadog-sampling-priority

对于 Lightstep,应转发 OpenTracing span 上下文请求头:

  • x-ot-span-context

对于 Stackdriver,您可以使用以下任一请求头来替代 B3 多请求头格式:

  • grpc-trace-bin:标准的 grpc 追踪头。
  • traceparent:追踪所用的 W3C 追踪上下文标准,受 OpenTelemetry 和日益增加的 Jaeger 客户端库所支持。
  • x-cloud-trace-context:被 Google Cloud 产品 API 所使用。

例如,如果您看基于 Python 语言的 productpage 服务这个例子,可以看到这个应用程序使用了 OpenTracing 库从 HTTP 请求中提取所需的请求头信息:

  1. def getForwardHeaders(request):
  2. headers = {}
  3. # 可以使用 opentracing span 填充 x-b3-*** 请求头
  4. span = get_current_span()
  5. carrier = {}
  6. tracer.inject(
  7. span_context=span.context,
  8. format=Format.HTTP_HEADERS,
  9. carrier=carrier)
  10. headers.update(carrier)
  11. # ...
  12. incoming_headers = ['x-request-id',
  13. 'x-ot-span-context',
  14. 'x-datadog-trace-id',
  15. 'x-datadog-parent-id',
  16. 'x-datadog-sampling-priority',
  17. 'traceparent',
  18. 'tracestate',
  19. 'x-cloud-trace-context',
  20. 'grpc-trace-bin',
  21. 'user-agent',
  22. 'cookie',
  23. 'authorization',
  24. 'jwt',
  25. ]
  26. # ...
  27. for ihdr in incoming_headers:
  28. val = request.headers.get(ihdr)
  29. if val is not None:
  30. headers[ihdr] = val
  31. return headers

在 review 这个应用中(Java)使用 requestHeaders 做了类似的事情:

  1. @GET
  2. @Path("/reviews/{productId}")
  3. public Response bookReviewsById(@PathParam("productId") int productId, @Context HttpHeaders requestHeaders) {
  4. // ...
  5. if (ratings_enabled) {
  6. JsonObject ratingsResponse = getRatings(Integer.toString(productId), requestHeaders);

当您在应用程序中进行下游调用时,请确保包含这些请求头。