2.SkyWalking源码阅读-了解SkyWalking的几个重要概念

1. Span

  1. Span代表一个完整的调用过程,类似于方法栈的栈针,如:helloService.hello()的栈针,包括了这个方法的出入参,环境等。Span可以表示一个RPC调用的栈针,包括请求、响应和调用上下文。
  2. SkyWalking将Span分为三种:
    1. EntrySpan
      1. 从字面理解这个是入口/进入Span。它是指谁的入口,又是进入谁呢?以客户端和服务端为例的话,它是服务端的概念,指服务端接收请求的入口,进入服务端。一般是将客户端的信息带入给服务端,返回响应数据给客户端。跨进程时使用。
    2. ExitSpan
      1. 从字面理解这个是出口/离开Span。还以客户端和服务端为例的话,它是客户端的概念,指客户端发送请求的出口,离开客户端。一般是将客户端信息带出给服务端,接收服务端响应数据。也是在跨进程时使用,与EntrySpan是一对。
    3. LocalSpan
      1. 从字面理解这个是本地Span。这个是在多线程时使用的,是一个子线程栈的栈顶元素,表示一个线程追踪的开始。跨线程时使用。

2. ContextCarrier

  1. 追踪上下文载体。跨进程时使用,用于装载上一个服务端系统的trace信息,传播给下一个服务端系统,使各个系统的trace信息可以关联。
  2. 举个例子:客户端调用服务端系统A,A又先后同步调用B,C。然后系统A返回响应给客户端。skywalking在系统A上生成分布式traceId,以及携带其他扩展或者用户的信息,装载到ContextCarrier对象上,传播给B,B会使用ContextCarrier上携带的分布式traceId,替换自己的分布式TraceId。这样A,B,C三个系统的追踪日志就关联上了。

3. ContextSnapshot

  1. 追踪上下文快照。跨线程时使用,用于记录主线程在创建Runnable/Callable/Supplier任务时主线程的追踪上下文数据,包括traceId等,set到子线程的任务Runnable/Callable中,用于多线程时关联追踪日志。

4. RunnableWrapper/CallableWrapper/SupplierWrapper

  1. 有没有想过如何拦截和增强多线程,使多线程可以被追踪?如果只是单纯的拦截所有jdk原生的Runnable/Callable,会导致除了业务系统以外的,不需要被追踪的线程也被追踪,浪费了大量的内存空间。如SkyWalking框架本身使用的线程池也会被追踪,但是这个数据对我们来说没有意义。

  2. 为了对业务线程任务和框架线程任务进行区分,SkyWalking定义了RunnableWrapper/CallableWrapper/SupplierWrapper这几个类,以及@TraceCrossThread注解,提供给业务线程使用,SkyWalking只对被Wrapper包装了的,和含有@TraceCrossThread注解的任务进行追踪。将需要追踪的线程任务包装成另一个类型,用来区分开jdk原生任务类型。

  3. 使用举例:

    //方式1
    @TraceCrossThread
    public static class MyCallable implements Callable {
        @Override
        public String call() throws Exception {
            return null;
        }
    }
    
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.submit(new MyCallable());
    
    //方式2
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    executorService.execute(RunnableWrapper.of(new Runnable() {
        @Override public void run() {
            //your code
        }
    }));
    
    //方式3
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setThreadFactory(r -> new Thread(RunnableWrapper.of(r)));
    
    //其他方式等等
    

5. TraceId

  1. 唯一定位一个调用链信息的id。
  2. SkyWalking在业务上定义了两种TraceId
    1. TraceSegmentId: 对应一个线程的trace id。
    2. DistributedTraceId: 唯一定位一个分布式操作的trace id。包括发出一个请求到收到响应的过程中,经历的所有分布式系统的trace数据,通过该id进行关联。

6. TraceSegment

  1. 一个TraceSegment对应一个线程内所有的追踪数据,这里重点是一个线程,即单线程。如果有两个线程就会对应有两个TraceSegment。一个TraceSegment包含多个Span。
  2. 一个TraceSegment对应一个traceSegmentId,用来唯一定位该TraceSegment。还持有一到多个关联的分布式操作的DistributedTraceId。

7. TracingContext

Trace的上下文,主要持有一个TraceSegment,以及模拟的Span栈,实际上应该说是TraceSegment的上下文。代码结构:

public class TracingContext implements AbstractTracerContext {
    //一个上下文持有一个TraceSegment
    private TraceSegment segment;
    //处于活动中,未完成状态的Span的栈集合
    private LinkedList activeSpanStack = new LinkedList<>();
    //根据id升序,还原一个TraceSegment内,多个span的先后执行关系。
    private int spanIdGenerator;
    
    //其他省略。。。
    private final CorrelationContext correlationContext;
    private final ExtensionContext extensionContext;
    private final SpanLimitWatcher spanLimitWatcher;

    TracingContext(String firstOPName, SpanLimitWatcher spanLimitWatcher) {
        //创建一个新的TraceSegment,包括新的traceId,DistributedTraceId。
        this.segment = new TraceSegment();
        //span id清零
        this.spanIdGenerator = 0;
        //默认同步模式,即单线程
        isRunningInAsyncMode = false;
        createTime = System.currentTimeMillis();
        running = true;

        this.correlationContext = new CorrelationContext();
        this.extensionContext = new ExtensionContext();
        this.spanLimitWatcher = spanLimitWatcher;
    }
}

你可能感兴趣的:(2.SkyWalking源码阅读-了解SkyWalking的几个重要概念)