OpenTracing-Java Scope与ScopeManager

本篇介绍一下OpenTraing-Java中比较重要的一个概念, ScopeScopeManager;

JAEGER-LOGO

PS: 原打算放到上篇文章中来写的,太长了,故单独又写了一篇。 转载请注明出处🙂;喜欢请一键三连哦😊;

一、 Scope 与 ScopeManager 是什么?

简单来说,OpenTracing-Java的实现中, 用ScopeScopeManager 来处理了OpenTracing中的上下文 (即:get_current_span 过程);

  • Scope:

Scope 对象是 Active Span的容器;通过Scope能拿到当前上下文内的Active Span; ThreadLocalScope 是Scope的一个实现,通过ThreadLocal 来存储;

  • ScopeManager:
    用来管理Scope, ScopeManager 抽象了 激活当前Span实例方法(via activate(Span)) 和 访问当前活跃Span实例的方法 (via activeSpan() );ThreadLocalScopeManager 是ScopeManager的一个实现;

看到这里, 不知道你是否和我有一样的疑问?

二、为什么要抽象出Scope的概念?

为什么要抽象出Scope的概念?直接使用ThreadLocal 存储Span不就可以了吗?

: 首先理解Scope是什么?Scope 是Active Span的一个容器, Scope 代表着当前活跃的Span; 是对当前活跃Span的一个抽象, 代表了当前上下文所处于的一个过程;

另外, ThreadLocalScope 还记录了 toRestore Span, 这样结束时,可以恢复到上一个Span的状态;

我理解如果只是 get_current_span() 逻辑的话,直接把 span 塞到 ThreadLocal里就可以在线程内传递了;但是ScopeManager看代码是这样实现的,ScopeManager 包含一个 Scope, Scope 又包含了 当前Span, recover Scope;我理解它的好处是: 这样就保证了,如果开启一个子Span(子span 会产生孙子span), 这样 子span 结束后,还可以回到 父span (这样可以继续产生以 父span 为基础的兄弟span), 如果只是ThreadLocal 里塞一个当前span的话,是解决不了这种情况的。

按我的理解画了一幅图:

OpenTracing Java 上下文管理

三、ScopeManager/Scope源码分析

3.1 ScopeManager

/**
* 激活当前 Span. 返回Scope(可以理解为 代表当前 Span 活跃的一个阶段)
* 
* Span 活跃期结束后,需要关闭 Scope, 推荐使用 try-with-resources 关闭
*
*/
Scope activate(Span span);

/**
* 返回当前 激活(active)状态Span, 无则返回null
*/
Span activeSpan();

3.2 ThreadLocalScopeManager

ThreadLocalScopeManager 是ScopeManager 的一个具体实现;使用原始的ThreadLocal 来存储 Active Span; ScopeManager中仅包含一个Scope( Active Span)

public class ThreadLocalScopeManager implements ScopeManager {

	// 当前Scope: 即当前上下文中的 active span
    final ThreadLocal<ThreadLocalScope> tlsScope = new ThreadLocal<ThreadLocalScope>();

    @Override
    public Scope activate(Span span) {
        return new ThreadLocalScope(this, span);
    }

    @Override
    public Span activeSpan() {
        ThreadLocalScope scope = tlsScope.get();
        return scope == null ? null : scope.span();
    }
}

补充: JaegerTracer

Tracer中的start方法(开启一个Span),使用了scopeManager 来获取上下文,从而来处理父子关系;

     @Override
    public JaegerSpan start() {
      JaegerSpanContext context;

      //  PS. 此处从ScopeManager获取上下文(线程)中,获取到激活的Span, 而后创建父子关系
      // Check if active span should be established as CHILD_OF relationship
      if (references.isEmpty() && !ignoreActiveSpan && null != scopeManager.activeSpan()) {
        asChildOf(scopeManager.activeSpan());
      }

      if (references.isEmpty() || !references.get(0).getSpanContext().hasTrace()) {
        context = createNewContext();
      } else {
        context = createChildContext();
      }
    
      ...
      return jaegerSpan;
    }

3.3 ThreadLocalScope

实现自Scope, 用ThreadLocal 来存储;

public class ThreadLocalScope implements Scope {
    private final ThreadLocalScopeManager scopeManager;
	// 当前 Active Span
    private final Span wrapped;
    // 上一Active Span,wrapped 结束时,会恢复到此Span
    // 为什么要有此字段,上面我们已经说过了
    private final ThreadLocalScope toRestore;

    ThreadLocalScope(ThreadLocalScopeManager scopeManager, Span wrapped) {
        this.scopeManager = scopeManager;
        this.wrapped = wrapped;
        this.toRestore = scopeManager.tlsScope.get();
        scopeManager.tlsScope.set(this);
    }

    @Override
    public void close() {
        if (scopeManager.tlsScope.get() != this) {
            // This shouldn't happen if users call methods in the expected order. Bail out.
            return;
        }

        scopeManager.tlsScope.set(toRestore);
    }

    Span span() {
        return wrapped;
    }
}

参考文档

OpenTracing Scope

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值