56. Span 生命周期

您可以通过brave.Tracer在 Span 上执行以下操作:

  • 开始:当您启动 span 时,将分配其 name 并记录开始时间戳。

  • :span 完成(记录 span 的结束 time),如果 span 被采样,则它有资格进行收集(对于 example,为 Zipkin)。

  • 继续:创建了一个新的 span 实例。它是继续它的副本。

  • 分离:span 不会停止或关闭。它只会从当前线程中删除。

  • 使用显式 parent 创建:您可以创建一个新的 span 并为其设置一个显式的 parent。

Spring Cloud Sleuth 为您创建Tracer的实例。在 order 中使用它,您可以自动装配它。

56.1 创造和完成 spans

您可以使用Tracer手动创建 spans,如下面的示例所示:

// Start a span. If there was a span present in this thread it will become
// the `newSpan`'s parent.
Span newSpan = this.tracer.nextSpan().name("calculateTax");
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(newSpan.start())) {
	// ...
	// You can tag a span
	newSpan.tag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	newSpan.annotate("taxCalculated");
} finally {
	// Once done remember to finish the span. This will allow collecting
	// the span to send it to Zipkin
	newSpan.finish();
}

在前面的示例中,我们可以看到如何创建 span 的新实例。如果此线程中已存在 span,则它将成为新 span 的 parent。

创建 span 后始终清洁。此外,始终完成您要发送给 Zipkin 的任何 span。

如果 span 包含大于 50 个字符的 name,则 name 将被截断为 50 个字符。你的名字必须明确而具体。大名称导致延迟问题,有时甚至是 exceptions。

56.2 继续 Spans

有时候,你不想创建一个新的 span,但你想继续一个。这种情况的一个例子可能如下:

  • AOP:如果在到达 aspect 之前已经创建了 span,您可能不想创建新的 span。

  • Hystrix:执行 Hystrix 命令很可能是当前处理的逻辑部分。事实上,它只是一个技术实现细节,您不一定要在跟踪中反映为一个单独的存在。

要_继续 span,您可以使用brave.Tracer,如下面的示例所示:

// let's assume that we're in a thread Y and we've received
// the `initialSpan` from thread X
Span continuedSpan = this.tracer.toSpan(newSpan.context());
try {
	// ...
	// You can tag a span
	continuedSpan.tag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	continuedSpan.annotate("taxCalculated");
} finally {
	// Once done remember to flush the span. That means that
	// it will get reported but the span itself is not yet finished
	continuedSpan.flush();
}

56.3 使用显式 Parent 创建 Span

您可能想要启动一个新的 span 并提供该 span 的显式 parent。假设 span 的 parent 在一个线程中,并且您想在另一个线程中启动一个新的 span。在 Brave 中,无论何时调用nextSpan(),它都会在 span 中创建一个 span,该 span 目前在范围内。您可以将 span 放在作用域中,然后调用nextSpan(),如下面的示例所示:

// let's assume that we're in a thread Y and we've received
// the `initialSpan` from thread X. `initialSpan` will be the parent
// of the `newSpan`
Span newSpan = null;
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(initialSpan)) {
	newSpan = this.tracer.nextSpan().name("calculateCommission");
	// ...
	// You can tag a span
	newSpan.tag("commissionValue", commissionValue);
	// ...
	// You can log an event on a span
	newSpan.annotate("commissionCalculated");
} finally {
	// Once done remember to finish the span. This will allow collecting
	// the span to send it to Zipkin. The tags and events set on the
	// newSpan will not be present on the parent
	if (newSpan != null) {
		newSpan.finish();
	}
}

在创建这样的 span 之后,你必须完成它。否则不报告(例如,Zipkin)。