How to trace GreptimeDB
GreptimeDB 使用 Rust 的 tracing 框架进行代码埋点,tracing 的具体原理和使用方法参见 tracing 的官方文档。
通过将 trace_id 等信息在整个分布式数据链路上透传,使得我们能够 记录整个分布式链路的函数调用链,知道每个被追踪函数的调用时间等相关信息,从而对整个系统进行诊断。
在 RPC 中定义 tracing 上下文
因为 tracing 框架并没有原生支持分布式追踪,我们需要手动将 trace_id 等信息在 RPC 消息中传递,从而正确的识别函数的调用关系。我们使用基于 w3c 的标准 将相关信息编码为 tracing_context ,将消息附在 RPC 的 header 中。主要定义在:
frontend与datanode交互:tracing_context定义在RegionRequestHeader中frontend与metasrv交互:tracing_context定义在RequestHeader中- Client 与
frontend交互:tracing_context定义在RequestHeader中
在 RPC 调用中传递 tracing 上下文
我们构建了一个 TracingContext 结构体,封装了与 tracing 上下文有关的操作。相关代码
GreptimeDB 在使用 TracingContext::from_current_span() 获取当前 tracing 上下文,使用 to_w3c() 方法将 tracing 上下文编码为符合 w3c 的格式,并将其附在 RPC 消息中,从而使 tracing 上下文正确的在分布式组件之中传递。
下面的例子说明了如何获取当前 tracing 上下文,并在构造 RPC 消息时正确传递参数,从而使 tracing 上下文正确的在分布式组件之中传递。
let request = RegionRequest {
header: Some(RegionRequestHeader {
tracing_context: TracingContext::from_current_span().to_w3c(),
..Default::default()
}),
body: Some(region_request::Body::Alter(request)),
};
在 RPC 消息的接收方,需要将 tracing 上下文正确解码,并且使用该上下文构建第一个 span 对函数调用进行追踪。比如下面的代码就将接收到的 RPC 消息中的 tracing_context 使用 TracingContext::from_w3c 方法正确解码。并使用 attach 方法将新建的 info_span!("RegionServer::handle_read") 附上了上下文消息,从而能够跨分布式组件对调用进行追 踪。
...
let tracing_context = request
.header
.as_ref()
.map(|h| TracingContext::from_w3c(&h.tracing_context))
.unwrap_or_default();
let result = self
.handle_read(request)
.trace(tracing_context.attach(info_span!("RegionServer::handle_read")))
.await?;
...