Brave 是一个库,用于捕获和向 Zipkin 报告分布式操作的延迟信息。大多数用户不直接使用 Brave。他们使用库或框架,而不是以 Brave 的名义。 这个模块包括一个跟踪程序,它创建并连接 Span 范围,对潜在分布式工作的延迟进行建模。它还包括在网络边界上传播跟踪上下文的库(例如,使用 HTTP 头)。
最重要的是,你需要一个 以下示例安装程序通过 HTTP(而不是 Kafka)将跟踪数据( Span )发送到 Zipkin: class MyClass { private final Tracer tracer; // Tracer will be autowired MyClass(Tracer tracer) { this.tracer = tracer; } void doSth() { Span span = tracer.newTrace().name("encode").start(); // ... } }
跟踪程序创建和连接跨范围的模型潜在分布式工作的延迟。它可以使用采样来减少过程中的开销,减少发送到 Zipkin 的数据量,或者两者兼而有之。 跟踪报告数据在完成时返回到 Zipkin,如果未完成,则不执行任何操作。开始一个范围后,你可以注解感兴趣的事件,或者添加包含详细信息或查找键的标记。 Span 具有一个上下文,其中包含将 Span 放置在树中表示分布式操作的正确位置的跟踪标识符。 跟踪从不离开进程的代码时,请在 Span 内运行它。 @Autowired Tracer tracer; // Start a new trace or a span within an existing trace representing an operation ScopedSpan span = tracer.startScopedSpan("encode"); try { // The span is in "scope" meaning downstream code such as loggers can see trace IDs return encoder.encode(); } catch (RuntimeException | Error e) { span.error(e); // Unless you handle exceptions, you might not know the operation failed! throw e; } finally { span.finish(); // always finish the span }
当需要更多功能或更精细的控制时,请使用 @Autowired Tracer tracer; // Start a new trace or a span within an existing trace representing an operation Span span = tracer.nextSpan().name("encode").start(); // Put the span in "scope" so that downstream code such as loggers can see trace IDs try (SpanInScope ws = tracer.withSpanInScope(span)) { return encoder.encode(); } catch (RuntimeException | Error e) { span.error(e); // Unless you handle exceptions, you might not know the operation failed! throw e; } finally { span.finish(); // note the scope is independent of the span. Always finish a span. } 以上两个例子在完成时报告的 Span 完全相同! 在过去的例子中, Span 将是一个新的根 Span ,或是一个现有跟踪中的下一个子级。 一旦有了 Span ,就可以向其添加标记。标记可以用作查找键或详细信息。例如,可以使用运行时版本添加标记,如下例所示: span.tag("clnt/finagle.version", "6.36.0");
当向第三方公开定制 Span 的能力时,首选 interface MyTraceCallback { void request(Request request, SpanCustomizer customizer); }
由于 for (MyTraceCallback callback : userCallbacks) {
callback.request(request, span);
}
有时,你不知道跟踪是否正在进行,也不希望用户执行空检查。 // The user code can then inject this without a chance of it being null. @Autowired SpanCustomizer span; void userCode() { span.annotate("tx.started"); ... }
RPC 跟踪通常由拦截器自动完成。在后台,他们添加与他们在 RPC 操作中的角色相关的标记和事件。 以下示例显示如何添加客户端 Span : @Autowired Tracing tracing; @Autowired Tracer tracer; // before you send a request, add metadata that describes the operation span = tracer.nextSpan().name(service + "/" + method).kind(CLIENT); span.tag("myrpc.version", "1.0.0"); span.remoteServiceName("backend"); span.remoteIpAndPort("172.3.4.1", 8108); // Add the trace context to the request, so it can be propagated in-band tracing.propagation().injector(Request::addHeader) .inject(span.context(), request); // when the request is scheduled, start the span span.start(); // if there is an error, tag the span span.tag("error", error.getCode()); // or if there is an exception span.error(exception); // when the response is complete, finish the span span.finish();
有时,你需要为异步操作建模,其中存在请求但没有响应。在正常的 RPC 跟踪中,使用 下面的示例显示客户端如何建模单向操作: @Autowired Tracing tracing; @Autowired Tracer tracer; // start a new span representing a client request oneWaySend = tracer.nextSpan().name(service + "/" + method).kind(CLIENT); // Add the trace context to the request, so it can be propagated in-band tracing.propagation().injector(Request::addHeader) .inject(oneWaySend.context(), request); // fire off the request asynchronously, totally dropping any response request.execute(); // start the client side and flush instead of finish oneWaySend.start().flush(); 以下示例显示服务器如何处理单向操作: @Autowired Tracing tracing; @Autowired Tracer tracer; // pull the context out of the incoming request extractor = tracing.propagation().extractor(Request::getHeader); // convert that context to a span which you can name and add tags to oneWayReceive = nextSpan(tracer, extractor.extract(request)) .name("process-request") .kind(SERVER) ... add tags etc. // start the server side and flush instead of finish oneWayReceive.start().flush(); // you should not modify this span anymore as it is complete. However, // you can create children to represent follow-up work. next = tracer.newSpan(oneWayReceive.context()).name("step2").start(); |