首页 > 编程语言 >源码角度了解Skywalking之Trace信息的生成

源码角度了解Skywalking之Trace信息的生成

时间:2022-10-04 19:31:15浏览次数:64  
标签:调用 span Trace 创建 operationName EntrySpan 源码 Skywalking 方法

源码角度了解Skywalking之Trace信息的生成

TraceId是分布式链路的一个信息,可以通过它定位一条链路

TraceId的生成

Skwalking的TraceId的生成是通过GlobalIdGenerator的generate()方法来生成的,

第一部分:具体是应用程序实例 ID

第二部分:线程 ID

第三部分:时间戳*10000+当前线程中的 seq,seq的值介于 0(包含)和 9999(包含)之间

三部分通过.来分隔开

我们知道SKywalking启动的是拦截实例方法的时候涉及到了InstMethodsInterWithOverrideArgs兰姐器和InstMethodsInter兰姐器,兰姐器的拦截方法中调用环绕兰姐器的beforeMethod()方法,这个方法中调用了ContextManager的createSpan()方法,afterMethod()方法中调用ContextManager的stopSpan()方法,我们看一下ContextManager这个类中涉及到的方法

ContextManager

ContextManager虽然也实现了BootService接口,但BootService的相关方法实现为空,ContextManager创建span的方法有三个,分别是createEntrySpan()方法、createLocalSpan()方法和createExitSpan()方法,EntrySpan是进入这个服务的时候创建的Span,比如消息队列的消费者入口,LocalSpan是本地方法调用的时候创建的Span,ExitSpan是离开这个服务创建的Span,比如发起远程调用的时候或者消息队列生产消息的时候

ContextManager的createEntrySpan()方法

ContextManager的createEntrySpan()方法

public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier) {
        AbstractSpan span;
        AbstractTracerContext context;
        operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
        if (carrier != null && carrier.isValid()) {
            SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
            samplingService.forceSampled();
            context = getOrCreate(operationName, true);
            span = context.createEntrySpan(operationName);
            context.extract(carrier);
        } else {
            context = getOrCreate(operationName, false);
            span = context.createEntrySpan(operationName);
        }
        return span;
    }
  1. 如果有上游服务,查找SamplingService实例调用forceSampled()方法强行采样
  2. 获取当前线程对应的TracingContext
  3. 调用TracingContext的createEntrySpan()方法创建EntrySpan,ActiveSpanStack栈存储了活动的span,如果这个栈中有span就放入栈中
  4. 提取上游的的Trace信息
  5. 如果没有上游服务就创建EntrySpan就可以了。

ContextManager的stopSpan()方法中关闭Span,调用ThreadLocal的remove()方法清除ThreadLocal防止内存泄露

TracingContext

TracingContext的createEntrySpan()方法

public AbstractSpan createEntrySpan(final String operationName) {
        if (isLimitMechanismWorking()) {
            NoopSpan span = new NoopSpan();
            return push(span);
        }
        AbstractSpan entrySpan;
        final AbstractSpan parentSpan = peek();
        final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId();
        if (parentSpan != null && parentSpan.isEntry()) {
            entrySpan = (AbstractTracingSpan)DictionaryManager.findEndpointSection()
                .findOnly(segment.getServiceId(), operationName)
                .doInCondition(new PossibleFound.FoundAndObtain() {
                    @Override public Object doProcess(int operationId) {
                        return parentSpan.setOperationId(operationId);
                    }
                }, new PossibleFound.NotFoundAndObtain() {
                    @Override public Object doProcess() {
                        return parentSpan.setOperationName(operationName);
                    }
                });
            return entrySpan.start();
        } else {
            entrySpan = (AbstractTracingSpan)DictionaryManager.findEndpointSection()
                .findOnly(segment.getServiceId(), operationName)
                .doInCondition(new PossibleFound.FoundAndObtain() {
                    @Override public Object doProcess(int operationId) {
                        return new EntrySpan(spanIdGenerator++, parentSpanId, operationId);
                    }
                }, new PossibleFound.NotFoundAndObtain() {
                    @Override public Object doProcess() {
                        return new EntrySpan(spanIdGenerator++, parentSpanId, operationName);
                    }
                });
            entrySpan.start();
            return push(entrySpan);
        }
    }

我们分析一下这一块的逻辑

  1. 调用isLimitMechanismWorking()方法判断是否超过最大的span数,默认是300,如果超过了最大数,创建NoopSpan对象,放入栈中返回
  2. 如果没有超过最大数,获取栈顶的span,也就是当前的span
  3. 如果父span不存在,创建EntrySpan对象,调用EntrySpan.start()开启span,start()方法其实就是设置startTime属性值为当前时间
  4. 如果父span存在就创建EntrySpan对象,开启span,然后压入栈中。

具体我们举个实例,看看这个三种类型的span是如何使用的

服务A

public void a() {
   b();
   c();
   d.d();
}

服务A有个a()方法,a()方法中依次调用了服务自己的b()方法、c()方法,和服务d的d()方法,这里的栈操作具体为:

  1. 请求经过tomcat插件创建EntrySpan入栈,调用start()开启span
  2. 调用b()方法的时候创建 LocalSpan对象入栈,调用start()开启span,a()方法结束的时候出栈
  3. 调用c()方法的时候同样创建 LocalSpan对象入栈,调用start()开启span,b()方法结束的时候出栈
  4. 调用d()方法的时候创建ExitSpan对象入栈,服务b调用结束的时候ExitSpan出栈
  5. 接着a()结束的时候EntrySpan出栈。

总结

这篇文章我们主要讲了Trace在一个请求过来的时候是怎么创建的,span的类型有三种,EntrySpan是进入这个服务的时候创建的Span,LocalSpan是本地方法调用的时候创建的Span,ExitSpan是离开这个服务创建的Span,深入分析了ContextManager这个类,这个类主要完成的是当前线程和TracingContext的绑定,TracingContext这个类就是创建span的类了。

❤️ 感谢大家

如果你觉得这篇内容对你挺有有帮助的话:

  1. 欢迎关注我❤️,点赞

    标签:调用,span,Trace,创建,operationName,EntrySpan,源码,Skywalking,方法
    From: https://blog.51cto.com/u_15460453/5731520

相关文章

  • 从vue源码中学习观察者模式
    摘要:源码解读设计模式系列文章将陆陆续续进行更新中~摘要:源码解读设计模式系列文章将陆陆续续进行更新中~观察者模式首先话题下来,我们得反问一下自己,什么是观察者模式......
  • 118-22-ZooKeeper 基础设施详解 和 服务启动流程源码分析_ev
         ......
  • PCA算法介绍及源码实现
    前言PCA(主成分分析)是十大经典机器学习算法之一。PCA是Pearson在1901年提出的,后来由Hotelling在1933年加以发展提出的一种多变量的统计方法。PCA算法介绍PCA(principalc......
  • Python 实现Tracert追踪TTL值
    Tracert命令跟踪路由原理是IP路由每经过一个路由节点TTL值会减一,假设TTL值=0时数据包还没有到达目标主机,那么该路由则会回复给目标主机一个数据包不可达,由此我们就可以获取......
  • skywalking 实现钉钉告警
    一、映射本地告警文件到docker-compose1.1、skywalking告警-指标说明#catconfig/oal/core.oalservice_resp_time#服务的响应时间service_sla#服务的http请求成功......
  • Python 实现Tracert追踪TTL值
    Tracert命令跟踪路由原理是IP路由每经过一个路由节点TTL值会减一,假设TTL值=0时数据包还没有到达目标主机,那么该路由则会回复给目标主机一个数据包不可达,由此我们就可以获......
  • 源码、反码、补码和精度损失
    数据类型转换,转换过程中可能导致溢出或损失精度1.源码:源码就是二进制的数字并且开头的一位代表符号位。例:(+1)的源码:00000001(-1)的源码:100000012.反码:正数......
  • React源码解读之任务调度
    前言简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的b......
  • react的useState源码分析
    前言简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的b......
  • skywalking 实现收集基于python的Django项目链路追踪案例
    一、python3环境设置1.1、安装python3apt-getupdateaptinstallpython3-pip-ypipinstall"apache-skywalking"[root@skywalking-agent-07~]#pipinstall"apache-s......