# 链路追踪

    随着业务规模和深度的拓展,微服务中的业务可能横跨多个应用,依赖的中间件也越来越多,任一节点出现问题,都可能导致整个业务请求出现波动或异常。

    正因为服务间存在错综复杂的关系,且多数项目并未妥善处理,一旦某个环节出现错误,排查过程也将变得异常复杂。

    链路追踪即用于解决此类问题,它可以分布式抓取多个节点的业务记录,并通过调用统一的请求 ID 将一次请求过程中的各个节点记录串联起来,方便排查请求过程中的业务瓶颈或异常点,从而在整个链路中快速获取异常点。

    请进入 微服务治理平台 > 诊断分析 > 链路追踪 进行操作。

    # 链路查询

    # 概念

    一条调用链可视为一个由多个 Span 组成的有向无环图(DAG 图)。

    一个 tracer 过程中,各 span 的关系如下:
            [Span A]  ←←←(the root span)
                |
         +------+------+
         |             |
     [Span B]      [Span C] ←←←(Span C 是 Span A 的孩子节点, ChildOf)
         |             |
     [Span D]      +---+-------+
                   |           |
               [Span E]    [Span F] >>> [Span G] >>> [Span H]
                                           ↑
                                           ↑
                                           ↑
                             (Span G 在 Span F 后被调用, FollowsFrom)
    

    某些情况下,下方这类基于时间轴的时序图能够更好地展示调用链。

    上述 tracer 与 span 的时间轴关系如下:
    ––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time
     [Span A···················································]
       [Span B··············································]
          [Span D··········································]
        [Span C········································]
             [Span E·······]        [Span F··] [Span G··] [Span H··]
    
    • Trace:一个 Trace 代表一个潜在的、分布式的、存在并行数据或并行执行轨迹(潜在的分布式、并行)的系统。一个 Trace 可视为有多个 Span 的有向无环图(DAG)。

    • Span:一个 Span 代表系统中具有开始时间和执行时长的逻辑运行单元。Span 之间通过嵌套或者顺序排列建立逻辑因果关系。一次调用中的某个节点或步骤类似于一层堆栈信息。Span 之间存在父子或并列关系以表明 Span 在整个调用中的生命周期。

    • Operation Name:每个 Span 均有一个操作名称,简单且具有高可读性(例如一个 RPC 方法名称,一个函数名称,或一个大型计算过程中的子任务或阶段)。Span 的操作名称应为一个抽象且通用的标识,是一个明确的、具有统计意义的名称。更具体的子类型描述,请使用 Tags。

    • Inter-Span References:一个 Span 可与一个或多个 Span 存在因果关系。Erda 遵循 OpenTracing 定义的两种关系:ChildOf 和 FollowsFrom。这两种引用类型代表了子节点和父节点间的直接因果关系。

      • ChildOf 引用:一个 Span 可能是一个父级 Span 的孩子,即 ChildOf 关系。在 ChildOf 引用关系下,父级 Span 某种程度上取决于子 Span。以下这些情况即构成 ChildOf 关系:

        • 一个 RPC 调用的服务端的 Span,和 RPC 服务客户端的 Span 构成 ChildOf 关系。

        • 一个 SQL insert 操作的 Span,和 ORM save 方法的 Span 构成 ChildOf 关系。

        • 许多可并行工作(或分布式工作)的 Span 均有可能为一个父级 Span 的子项,它将合并所有子 Span 的执行结果,并在指定期限内返回。

        以下为合理表述 ChildOf 关系的父子节点关系的时序图:

            [-Parent Span---------]
                 [-Child Span----]
            [-Parent Span--------------]
                 [-Child Span A----]
                  [-Child Span B----]
                [-Child Span C----]
                 [-Child Span D---------------]
                 [-Child Span E----]
        
      • FollowsFrom 引用: 一些父级节点不以任何方式依赖于其子节点的执行结果。在此情况下,这些子 Span 和父 Span 之间即为 FollowsFrom 的因果关系。FollowsFrom 关系可分为众多不同的子类型。

        以下为合理表述 FollowFrom 关系的父子节点关系的时序图:

            [-Parent Span-]  [-Child Span-]
            [-Parent Span--]
             [-Child Span-]
            [-Parent Span-]
                        [-Child Span-]
        

    # 实践

    数据接入请参见 Agent 使用指导

    对于 Java 服务而言,Erda 采用 Agent 自动探针的方式采集链路信息。您只需通过 Erda 提供的流水线 Action 进行服务部署,即可自行集成 Agent。自动采集后的追踪数据可通过链路查询查看。

    已支持的组合查询方式如下:

    • 持续时间
    • 链路状态
    • 过滤规则
      • 服务名
      • 追踪 ID
      • RPC Method
      • HTTP Path

    点击可查看具体的链路信息。

    提示

    点击链路图中的 Span 节点可查看调用过程中的关键信息,如属性、事件以及关联服务。

    • 属性:Span 的标签和字段。
    • 事件:记录一些 Span 事件,例如耗时。
    • 关联服务:可快速查看当前 Span 采集的服务相关核心指标数据。

    服务每次与外界交互时都会生成一个 Span,例如,服务接收到一个请求,服务发起一次 RPC 调用,服务发起一次 DB 调用。

    如上图所示:

    • 服务 A 收到一个请求会生成一个 Span 1。
    • 服务 A 发起一个 RPC 请求调用服务 B 会生成一个 Span 2,其父 Span 为 Span 1。
    • 服务 B 收到服务 A 的 RPC 请求后生成 Span 3,其父 Span 为 Span 2。 两者的开始/结束时间差即网络耗时。
    • 服务 A 收到 RPC 响应后发起 DB 调用会再生成一个 Span 4,其父 Span 为 Span 1,其兄弟 Span 为 Span 2,Span 4 与 Span 2 为平级关系。

    # 链路调试

    链路调试可与链路查询配合使用。例如,通过链路查询发现一条异常 Trace 时,距离异常发生已过去一段时间,某些数据可能已经丢失。此时可通过链路调试快速还原一条新的 Trace,继续定位问题。