天天看点

源码角度了解Skywalking之Trace信息的采样源码角度了解Skywalking之Trace信息的采样

源码角度了解Skywalking之Trace信息的采样

一条请求链路产生那么多trace信息,skywalking是每条trace都进行采集吗?显然不是,这就涉及到skywalking的采样了,我们看一下SKywalking是怎么对Trace信息进行采样的

采样

采样涉及到的类是SamplingService,在上篇文章中我们分析ContextManager的createEntrySpan()方法创建EntrySpan的过程中,调用了SamplingService的forceSampled()方法进行采样,具体就是samplingFactorHolder属性进行加1操作,记录采样次数。

SamplingService同样是BootService的实现类,它负责如何对 TraceSegment进行采样。每个 TraceSegment 都已被跟踪,但考虑到序列化反序列化的 CPU 成本和网络带宽问题,如果采样开启,代理不会将它们全部发送到收集器。

采样是在Config的Agent的SAMPLE_N_PER_3_SECS参数值,它表示在 3 秒内采样数,默认情况下,负数或零表示关闭。

定时重置采样次数

SamplingService的boot()方法:

public void boot() throws Throwable {
        if (scheduledFuture != null) {
            
            scheduledFuture.cancel(true);
        }
        if (Config.Agent.SAMPLE_N_PER_3_SECS > 0) {
            on = true;
            this.resetSamplingFactor();
            ScheduledExecutorService service = Executors
                .newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("SamplingService"));
            scheduledFuture = service.scheduleAtFixedRate(new RunnableWithExceptionProtection(new Runnable() {
                @Override
                public void run() {
                    resetSamplingFactor();
                }
            }, new RunnableWithExceptionProtection.CallbackWhenException() {
                @Override public void handle(Throwable t) {
                    logger.error("unexpected exception.", t);
                }
            }), 0, 3, TimeUnit.SECONDS);
            logger.debug("Agent sampling mechanism started. Sample {} traces in 3 seconds.", Config.Agent.SAMPLE_N_PER_3_SECS);
        }
    }
           
  1. 如果boot()方法被调用了两次,就取消旧的那一个,这种情况主要在测试用例中出现
  2. 先重置采样次数,判断如果配置的SAMPLE_N_PER_3_SECS参数大于0,表示开启了采样,把on设置为true,创建定时线程池,每3s重置采样次数,创建RunnableWithExceptionProtection实例线程,线程调用resetSamplingFactor()方法重置采用次数

ContextManager在创建Span的过程中需要获取TraceContext对象,调用了ContextManagerExtendService的createTraceContext()方法来创建TraceContext,如果是强制采样或者调用trySampling()进行判断可以进行采样,就创建TracingContext对象,否则调用IgnoredTracerContext对象

是否可以采样

看一下SamplingService的trySampling()方法:

public boolean trySampling() {
        if (on) {
            int factor = samplingFactorHolder.get();
            if (factor < Config.Agent.SAMPLE_N_PER_3_SECS) {
                boolean success = samplingFactorHolder.compareAndSet(factor, factor + 1);
                return success;
            } else {
                return false;
            }
        }
        return true;
    }
           

SamplingService的trySampling()方法主要是如果采样机制开启,判断是否可以成功获取默认采样因子,具体这里samplingFactorHolder属性值与Config.Agent.SAMPLE_N_PER_3_SECS配置类中设置的值进行比较如果,如果比它小就可以进行采样,返回true

强制采样

SamplingService的forceSampled()方法进行强制采样

public void forceSampled() {
        if (on) {
            samplingFactorHolder.incrementAndGet();
        }
    }
           

总结

❤️ 感谢大家

  1. 欢迎关注我❤️,点赞👍🏻,评论🤤,转发🙏
  2. 有不当之处欢迎批评指正。