原理图

图编号: 第一排序规则: 自左向右递增 第二排序规则: 自上向下递增

栈机制解说

详解一个Http请求经过APP-1(tomcat-> springmvc -> dubbo provider)和APP-2(dubbo consumer)的调用链路

  • 图1: TomcatInvokeInterceptor.beforeMethod创建EntrySpan,内部创建TracerContext上下文,TracerContext内部创建TraceSegment, EntrySpan加入TracerContext.activeSpanStack.此时span的最大栈深度和当前栈深度都是1
  • 图2: MVC插件beforeMethod发现tomcat已经创建entrySpan,则复用该span,此时span的最大栈深度和当前栈深度都是2
  • 图3: DubboInterceptor.before发现即将跨进程,创建ExitSpan(栈深等于1)并加入activeSpanStack

  • 图4: 到达新的进程(dubboProvider端),创建一个EntrySpan,栈深为1
  • 图5: DubboInterceptor.afterMethod,离开时栈深减一等于0
  • 图6: 当entrySpan的栈深度为0 ,则将其加入Segment.span
  • 图7: 发现activeSpanStack中没有span,说明未来不会从activeSpanStack弹出span到Segment,触发Segment上报到OAP
  • 图8: ContextManager.stopSpan清空TracerContext和RuntimeContext

  • 图9: 此时serviceB处理完毕,回到serviceA的dubbo消费端DubboInterceptor.afterMethod执行后stackDepth减一等于零
  • 图10: 发现stackDepth为零,则将该ExitSpan移除activeSpanStack加入Segment,由于activeSpanStack还有一个EntrySpan,不进行OAP数据上报

  • 图11: 此时到达MVC的afterMethod,最大栈深度为2但当前栈深度减一,由于当前栈深度不为零,则不进行出栈处理
  • 图12: TomcatInvokeInterceptor.afterMethod执行后发现当前栈深度减一等于零
  • 图13: 栈深度为0,则将activeSpanStack中的EntrySpan弹栈后加入Segment
  • 图14: 由于activeSpanStack中无元素,触发Segment上报OAP
  • 图15: 整个链路调用完毕清空TracerContext和RuntimeContext

在这里插入图片描述

名词含义

名称 解释
TracerContext 当请求到达一个新的进程时,skywalking会创建或者反序列化ContextCarrier获得TracerContext
EntrySpan 到达新进程或流量入口span一般称为入口Span,其有两个属性currentMaxDepth和stackDepth
TracerContext.activeSpanStack 新创建的Span并没有加入Segment,而是加入activeSpanStack
EntrySpan.currentMaxDepth与stackDepth tomcat和springMvc都适合做entrySpan,此时mvc复用tomcat的EntrySpan,但stackDepth++,currentMaxDepth++
TracerContext.segment 一个segment表示一条跨进程与线程的调用链路
Segment.spans 当进入插件拦截方法EntrySpan的stackDepth++,当离开插件拦截方法EntrySpan的stackDepth–,当stackDepth等于零,则从activeSpanStack弹出并加入Segment.spans

总结

  • Segment链路的数据来自于TracerContext
  • 每个插件都将Span加入activeSpanStack中,进入插件拦截方法压栈或者stackDepth++,离开插件拦截方法出栈或者stackDepth–
  • stackDepth = 0则弹栈移入Segment
  • 当activeSpanStack无元素则向OAP上报链路数据
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐