51. Span 生命周期

您可以通过org.springframework.cloud.sleuth.Tracer接口在 Span 上执行以下操作:

  • 开始 - 当你启动 span 时,会分配 name 并记录开始时间戳。

  • - span 完成(span 的结束 time 被记录),如果 span 是可导出的那么它将有资格收集到 Zipkin。 span 也从当前线程中删除。

  • 继续 - 将创建一个新的 span 实例,而它将是它继续的实例的副本。

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

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

Spring 为您创建Tracer的实例。在_to 使用它你只需要自动装配它。

51.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.createSpan("calculateTax");
try {
	// ...
	// You can tag a span
	this.tracer.addTag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	newSpan.logEvent("taxCalculated");
} finally {
	// Once done remember to close the span. This will allow collecting
	// the span to send it to Zipkin
	this.tracer.close(newSpan);
}

在这个 example 中,我们可以看到如何创建 span 的新实例。假设此线程中已存在 span,那么它将成为该 span 的 parent。

创建 span 后始终清洁!如果要将其发送到 Zipkin,请不要忘记关闭 span。

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

51.2 继续 spans

有时你不想创建一个新的 span,但你想继续一个。 这种情况的例子可能是(当然这一切都取决于 use-case):

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

  • Hystrix - 执行 Hystrix 命令很可能是当前处理的逻辑部分。事实上,这只是一个技术性的实现细节,你不一定要在跟踪作为一个单独的存在时反映出来。

span 的持续实例等于它继续的实例:

Span continuedSpan = this.tracer.continueSpan(spanToContinue);
assertThat(continuedSpan).isEqualTo(spanToContinue);

要继续 span,您可以使用Tracer界面。

// let's assume that we're in a thread Y and we've received
// the `initialSpan` from thread X
Span continuedSpan = this.tracer.continueSpan(initialSpan);
try {
	// ...
	// You can tag a span
	this.tracer.addTag("taxValue", taxValue);
	// ...
	// You can log an event on a span
	continuedSpan.logEvent("taxCalculated");
} finally {
	// Once done remember to detach the span. That way you'll
	// safely remove it from the current thread without closing it
	this.tracer.detach(continuedSpan);
}

创建 span 后始终清洁!如果在一个线程(e.g. 线程 X)中开始完成某些工作并且它正在等待其他线程(e.g. Y,Z)完成,请不要忘记分离 span。然后,线程 Y,Z 中的 spans 应在其工作结束时分离。收集结果时,应关闭线程 X 中的 span。

51.3 使用显式 parent 创建 spans

您可能希望启动一个新的 span 并提供该 span 的显式 parent。假设 span 的 parent 在一个线程中,并且您想在另一个线程中启动一个新的 span。 Tracer接口的startSpan方法是您要查找的方法。

// 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 = this.tracer.createSpan("calculateCommission", initialSpan);
try {
	// ...
	// You can tag a span
	this.tracer.addTag("commissionValue", commissionValue);
	// ...
	// You can log an event on a span
	newSpan.logEvent("commissionCalculated");
} finally {
	// Once done remember to close 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
	this.tracer.close(newSpan);
}

创建了这样一个 span 之后记得关闭它。否则,您会在日志中看到很多警告,这些警告与当前线程中存在 span 而不是您要关闭的线程有关。更糟糕的是你的 spans 不会被正确关闭,因此不会被收集到 Zipkin。