Java分布式跟踪系统Zipkin(三):Brave源码分析-Tracing

上一篇博文中,我们了解了Brave框架的基本使用,并且分析了跟Tracer相关的部分源代码。这篇博文我们接着看看Tracing的初始化及相关类的源代码

public class TraceDemo {

    public static void main(String[] args) {
	Sender sender = OkHttpSender.create("http://localhost:9411/api/v2/spans");
	AsyncReporter asyncReporter = AsyncReporter.builder(sender)
		.closeTimeout(500, TimeUnit.MILLISECONDS)
		.build(SpanBytesEncoder.JSON_V2);

	Tracing tracing = Tracing.newBuilder()
		.localServiceName("tracer-demo")
		.spanReporter(asyncReporter)
		.propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "user-name"))
		.currentTraceContext(ThreadContextCurrentTraceContext.create())
		.build();
	Tracer tracer = tracing.tracer();
	// ...
    }
}

Brave中各个组件创建大量使用的builder设计模式,Tacing也不例外,先来看下Tracing.Builder

Tracing.Builder

public static final class Tracing.Builder {
    String localServiceName;
    Endpoint localEndpoint;
    Reporter<zipkin2.Span> reporter;
    Clock clock;
    Sampler sampler = Sampler.ALWAYS_SAMPLE;
    CurrentTraceContext currentTraceContext = CurrentTraceContext.Default.inheritable();
    boolean traceId128Bit = false;
    boolean supportsJoin = true;
    Propagation.Factory propagationFactory = Propagation.Factory.B3;
    
    public Tracing build() {
      if (clock == null) clock = Platform.get();
      if (localEndpoint == null) {
        localEndpoint = Platform.get().localEndpoint();
        if (localServiceName != null) {
          localEndpoint = localEndpoint.toBuilder().serviceName(localServiceName).build();
        }
      }
      if (reporter == null) reporter = Platform.get();
      return new Default(this);
    }

    Builder() {
    }
}

Tracing中依赖的几个重要类

  • Endpoint – IP,端口和应用服务名等信息
  • Sampler – 采样器,根据traceId来判断是否一条trace需要被采样,即上报到zipkin
  • TraceContext – 包含TraceId,SpanId,是否采样等数据
  • CurrentTraceContext – 是一个辅助类,可以用于获得当前线程的TraceContext
  • Propagation – 是一个可以向数据携带的对象carrier上注入(inject)和提取(extract)数据的接口
  • Propagation.Factory – Propagation的工厂类

前面TraceDemo例子中,我们初始化Tracing时设置了localServiceName,spanReporter,propagationFactory,currentTraceContext 其中spanReporter为AsyncReporter我们上一篇已经分析过其源代码了,在build方法中可以看到,其默认实现是Platform,默认会将Span信息用logger进行输出,而不是上报到zipkin中

  @Override public void report(zipkin2.Span span) {
    if (!logger.isLoggable(Level.INFO)) return;
    if (span == null) throw new NullPointerException("span == null");
    logger.info(span.toString());
  }

Sampler

采样器,根据traceId来判断是否一条trace需要被采样,即上报到zipkin

public abstract class Sampler {

  public static final Sampler ALWAYS_SAMPLE = new Sampler() {
    @Override public boolean isSampled(long traceId) {
      return true;
    }

    @Override public String toString() {
      return "AlwaysSample";
    }
  };

  public static final Sampler NEVER_SAMPLE = new Sampler() {
    @Override public boolean isSampled(long traceId) {
      return false;
    }

    @Override public String toString() {
      return "NeverSample";
    }
  };

  /** Returns true if the trace ID should be measured. */
  public abstract boolean isSampled(long traceId);

  /**
   * Returns a sampler, given a rate expressed as a percentage.
   *
   * <p>The sampler returned is good for low volumes of traffic (<100K requests), as it is precise.
   * If you have high volumes of traffic, consider {@link BoundarySampler}.
   *
   * @param rate minimum sample rate is 0.01, or 1% of traces
   */
  public static Sampler create(float rate) {
    return CountingSampler.create(rate);
  }
}

Sampler.ALWAYS_SAMPLE 永远需要被采样 Sampler.NEVER_SAMPLE 永远不采样

Sampler还有一个实现类 CountingSampler可以指定采样率,如CountingSampler.create(0.5f)则对50%的请求数据进行采样,里面用到了一个算法,这里不展开分析了。

TraceContext

包含TraceId,SpanId,是否采样等数据

在Tracer的newRootContext方法中有这样一段代码,通过newBuilder来构建TraceContext对象

  TraceContext newRootContext(SamplingFlags samplingFlags, List<Object> extra) {
    long nextId = Platform.get().randomLong();
    Boolean sampled = samplingFlags.sampled();
    if (sampled == null) sampled = sampler.isSampled(nextId);
    return TraceContext.newBuilder()
        .sampled(sampled)
        .traceIdHigh(traceId128Bit ? Platform.get().nextTraceIdHigh() : 0L).traceId(nextId)
        .spanId(nextId)
        .debug(samplingFlags.debug())
        .extra(extra).build();
  }

TraceContext中有以下一些属性

  • traceIdHigh – 唯一标识trace的16字节id,即128-bit
  • traceId – 唯一标识trace的8字节id
  • parentId – 父级Span的spanId
  • spanId – 在某个trace中唯一标识span的8字节id
  • shared – 如果为true,则表明需要从其他tracer上共享span信息
  • extra – 在某个trace中相关的额外数据集

还有继承自SamplingFlags的两个属性

  • sampled – 是否采样
  • debug – 是否为调试,如果为true时,就算sampled为false,也表明该trace需要采样(即可以覆盖sampled的值)

TraceContext中还定义了两个接口Inj

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值