在ASM中实现分布式跟踪

服务网格ASM集成了阿里云可观测链路OpenTelemetry版,为分布式应用的开发者提供了完整的调用链路还原、调用请求量统计、链路拓扑、应用依赖分析等能力,可以帮助开发者快速分析和诊断分布式应用架构下的性能瓶颈,提升开发诊断效率。本文介绍如何在ASM中实现分布式跟踪。

背景信息

分布式跟踪是一种用于对应用程序进行概要分析和监视的方法,尤其是适用于使用微服务架构构建的应用程序。使用服务网格时,Istio代理Envoy可以自动生成和发送Span信息,但为了确保这些 Span 能正确关联到同一个跟踪中,应用程序仍然需要传播相应的HTTP标头。在代理发送Span时,应用程序必须收集特定的标头并将其从传入请求传播到所有传出请求。OpenTelemetry支持不同的传播器,在不同的传播器中,特定的标头格式定义也有所不同,以下列出了OpenTelemetry支持的传播器以及对应的标头。

B3传播器

  • x-request-id

  • x-b3-traceid

  • x-b3-spanid

  • x-b3-parentspanid

  • x-b3-sampled

  • x-b3-flags

  • x-ot-span-context

W3C Trace Context传播器

  • traceparent

  • tracestate

说明

ASM在1.18.0.124版本之前默认采用的B3传播器,之后默认采用W3C Trace Context传播器。

前提条件

示例解析

在Bookinfo书评应用中,以Python语言实现的productpage服务使用了OpenTracing库,并利用B3传播器标头格式从HTTP请求中提取了所需的标头。

def getForwardHeaders(request):
    headers = {}
    # x-b3-*** headers can be populated using the opentracing span
    span = get_current_span()
    carrier = {}
    tracer.inject(
        span_context=span.context,
        format=Format.HTTP_HEADERS,
        carrier=carrier)
    headers.update(carrier)
    # ...

    incoming_headers = ['x-request-id']

    # ...

    for ihdr in incoming_headers:
        val = request.headers.get(ihdr)
        if val is not None:
            headers[ihdr] = val
    return headers

以Java语言实现的reviews服务是也可以看到使用了B3传播器的HTTP标头。

@GET
@Path("/reviews/{productId}")
public Response bookReviewsById(@PathParam("productId") int productId,
                            @HeaderParam("end-user") String user,
                            @HeaderParam("x-request-id") String xreq,
                            @HeaderParam("x-b3-traceid") String xtraceid,
                            @HeaderParam("x-b3-spanid") String xspanid,
                            @HeaderParam("x-b3-parentspanid") String xparentspanid,
                            @HeaderParam("x-b3-sampled") String xsampled,
                            @HeaderParam("x-b3-flags") String xflags,
                            @HeaderParam("x-ot-span-context") String xotspan) {

  if (ratings_enabled) {
    JsonObject ratingsResponse = getRatings(Integer.toString(productId), user, xreq, xtraceid, xspanid, xparentspanid, xsampled, xflags, xotspan);

访问示例

在浏览器地址栏输入http://{入口网关服务的IP地址}/productpage,可以看到Bookinfo应用的页面。

查看应用列表

应用列表页面展示了所有被监控应用的健康度得分、本日请求数、本日错误数等关键指标。您还可以为应用设置自定义标签,从而通过标签进行筛选。

  1. 登录可观测链路OpenTelemetry版控制台

  2. 在左侧导航栏,单击应用列表,然后在页面上方,选择目标地域。应用列表

查看应用详情

应用详情页面可展示应用在所部属的每一台机器上的关键性能指标、调用拓扑图和调用链路。

  1. 登录可观测链路OpenTelemetry版控制台

  2. 在左侧导航栏,单击应用列表,然后在页面上方选择目标地域,单击目标应用名称。

  3. 在左侧导航栏,单击应用详情,在左侧的机器列表中单击全部或一台以IP地址标识的机器。

    您可以在概览页签查看调用拓扑图和关键性能指标;在调用链路页签查看该应用在所选机器上的调用链路列表,按耗时降序排列,最多可列出100个调用链路。调用链路

查看调用链瀑布图

调用链路的瀑布图展示了调用链路的日志产生时间、状态、IP址/机器名称、服务名、时间轴等信息。

  1. 应用详情页面,单击调用链路页签,然后单击目标链路的Trace ID。

  2. 在新弹出的调用链路页面,查看该调用链路的瀑布图。

    说明
    • IP地址字段显示的是IP地址还是机器名称,取决于应用设置页面上的显示配置。更多信息,请参见管理应用和标签

    • 将鼠标悬浮于服务名上,还可以查看该服务的时长、开始时间、Tag和日志事件等信息。更多信息,请参见应用详情

    瀑布图

FAQ

为什么在ASM中将链路追踪数据采集到可观测链路OpenTelemetry版,却仍然看不到调用链路?

  1. 查看链路推送日志。

    1. 获取集群KubeConfig并通过kubectl工具连接集群

    2. 执行以下命令,查看istio-system命名空间下tracing-on-external-zipkin的链路推送日志。

      kubectl logs "$(kubectl get pods -n istio-system  -l app=tracing -o jsonpath='{.items[0].metadata.name}')" -n istio-system -c  nginx

      可以看到链路推送日志的状态码为406。日志

  2. 查看额度请求数量和昨日请求数量。

    1. 登录可观测链路OpenTelemetry版控制台

    2. 在左侧导航栏,单击集群配置,查看额度请求数量和昨日请求数量。

      额度配置

    根据以上结果,可以看到服务的请求数量大于链路追踪的额度请求数量。

  3. 修改额度请求数量。

    如果服务的请求数量大于链路追踪的额度请求数量,上报的数据将会被丢弃,您将看不到服务的调用链路。您需要修改额度配置,使得额度请求数量大于服务请求数量。

    1. 在可观测链路OpenTelemetry版控制台左侧导航栏,单击集群配置

    2. 集群配置页签的额度配置区域修改配置额度,使得额度请求数量大于服务请求数量,然后单击保存

    3. 提示对话框,单击确认

为什么traceid经过ASM网关或Sidecar后发生了改变?

该问题可能是由于发起端应用在发起请求时携带的特定传播标头不全,Envoy认为追踪信息不完整,导致重新生成了传播标头。若您希望自行生成traceid,对于B3传播器来说,请求中至少需要携带x-b3-trace-id和x-b3-spanid两个标头;对于W3C Trace Context传播器来说,请求中至少需要携带traceparent标头。