™技术博客

apm | Tracing原理剖析

2021年6月14日

Tracing Agent原理

以 User调用project-test-projectA为例

1
http://ali03:8888/projectA/admin

User -> Tomcat7 -> SpringMvc(projectA/{name})-> 线程内调用 -> FeignClient(projectB/{name})

EntrySpan

  • ContextManager.createEntrySpan()

  • TracingContext#createEntrySpan()
    检测EntrySpan是否已创建,如果是,则不会创建新的EntrySpan,只是重新调用一下其start()方法即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public AbstractSpan createEntrySpan(final String operationName) {
    // 默认配置下,每个TraceSegment只能放300个Span
    if (isLimitMechanismWorking()) {
    NoopSpan span = new NoopSpan(); // 超过300就放NoopSan
    return push(span); // 将Span记录到activeSpanStack栈中
    }
    AbstractSpan entrySpan;
    TracingContext owner = this;
    final AbstractSpan parentSpan = peek(); // 读取栈顶Span,即当前Span
    final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
    if (parentSpan != null && parentSpan.isEntry()) {

    profilingRecheck(parentSpan, operationName);
    // 更新operationName
    parentSpan.setOperationName(operationName);
    entrySpan = parentSpan;
    // 重新调用start()方法,strart()方法会重置operationName之外的其他字段
    return entrySpan.start();
    } else {
    // 新建EntrySpan对象,spanIdGenerator生成Span ID并递增
    entrySpan = new EntrySpan(
    spanIdGenerator++, parentSpanId,
    operationName, owner
    );
    // 调用start方法,第一次调用start()方法会设置startTime
    entrySpan.start();
    // 将新建的Span添加到activeSpanStack栈的栈顶
    return push(entrySpan);
    }
    }

    LocalSpan

  • ContextManager#createLocalSpan()

  • TracingContext#createLocalSpan()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (isLimitMechanismWorking()) {
NoopSpan span = new NoopSpan();
return push(span);
}
// 从activeSpanStack栈顶获取当前Span
AbstractSpan parentSpan = peek();
final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
// 新建LocalSpan对象
AbstractTracingSpan span = new LocalSpan(spanIdGenerator++, parentSpanId, operationName, this);
// 调用start方法,第一次调用start()方法会设置startTime
span.start();
// 将新建的Span添加到activeSpanStack栈的栈顶
return push(span);
}

ExitSpan

  • ContextManager#createExitSpan()
  • TraingContext#createExitSpan()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public AbstractSpan createExitSpan(final String operationName, final String remotePeer) {
if (isLimitMechanismWorking()) {
NoopExitSpan span = new NoopExitSpan(remotePeer);
return push(span);
}

AbstractSpan exitSpan;
// 从activeSpanStack栈顶获取当前Span
AbstractSpan parentSpan = peek();
TracingContext owner = this;
if (parentSpan != null && parentSpan.isExit()) {
// 当前Span已经是ExitSpan,则不再新建ExitSpan,而是调用其start()方法
exitSpan = parentSpan;
} else {
// 当前Span不是ExitSpan,就新建一个ExitSpan
final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
exitSpan = new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer, owner);
// 将新建的ExitSpan入栈
push(exitSpan);
}
// 调用start()方法
exitSpan.start();
return exitSpan;
}

stopSpan()

  • ContextManager.stopSpan()
  • TracingContext#stopSpan()
    会将当前activeSpanStack栈顶的Span关闭并出栈,同时整个activeSpanStack栈空了之后,会尝试关闭当前TraceSegment。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public boolean stopSpan(AbstractSpan span) {
    // 获取当前栈顶的Span对象
    AbstractSpan lastSpan = peek();
    if (lastSpan == span) { // 只能关闭当前活跃的Span对象,否则抛出异常
    if (lastSpan instanceof AbstractTracingSpan) {
    AbstractTracingSpan toFinishSpan = (AbstractTracingSpan) lastSpan;
    //添加span到segment中 并记录结束时间
    if (toFinishSpan.finish(segment)) { // 尝试关闭Span
    // 当Span完全关闭之后,会将其出栈(即从activeSpanStack中删除)
    pop();
    }
    } else {
    pop();
    }
    } else {
    throw new IllegalStateException("Stopping the unexpected span = " + span);
    }
    //如果该节点是最后一个节点
    finish();

    return activeSpanStack.isEmpty();
    }

    关闭TraceSegment

    放入内存队列中,等待发送collector
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    private void finish() {
    if (isRunningInAsyncMode) {
    asyncFinishLock.lock();
    }
    try {
    boolean isFinishedInMainThread = activeSpanStack.isEmpty() && running;
    if (isFinishedInMainThread) {
    /*
    * Notify after tracing finished in the main thread.
    */
    TracingThreadListenerManager.notifyFinish(this);
    }
    //TraceSegmentServiceClient#afterFinished()放入内存队列中
    if (isFinishedInMainThread && (!isRunningInAsyncMode || asyncSpanCounter == 0)) {
    TraceSegment finishedSegment = segment.finish(isLimitMechanismWorking());
    TracingContext.ListenerManager.notifyFinish(finishedSegment);
    running = false;
    }
    } finally {
    if (isRunningInAsyncMode) {
    asyncFinishLock.unlock();
    }
    }
    }
Tags: apm

扫描二维码,分享此文章