Dapper and Blkin
Dapper 是 Google 生产环境下的分布式跟踪系统,其设计之初参考了 Magpie 和 X-Trace 等分布式系统的理念,具有低损耗、应用透明的、大范围部署等特点。本文介绍 Dapper 的基本原理及其一个 C++ 开源实现 Blkin。
Dapper 原理
span
span 对应分布式系统中的一个进程或微服务(相互之间通过RPC进行通信),每个 span 结构中应包含进程或微服务的标识(通常是服务名 name),RPC请求中携带的 parent_span_id,及当前进程或微服务生成的 span_id。
annotation
annotation 对应每一条 Trace Log 中有用的信息,一般为事件或Key-Value对,常见的事件包含:
const char* const CLIENT_SEND = "cs";
const char* const CLIENT_RECV = "cr";
const char* const SERVER_SEND = "ss";
const char* const SERVER_RECV = "sr";
const char* const WIRE_SEND = "ws";
const char* const WIRE_RECV = "wr";
const char* const CLIENT_SEND_FRAGMENT = "csf";
const char* const CLIENT_RECV_FRAGMENT = "crf";
const char* const SERVER_SEND_FRAGMENT = "ssf";
const char* const SERVER_RECV_FRAGMENT = "srf";
应用程序关心的其它信息可以记录为 Key-Value 类型日志。
trace id
通过 span 和 annotation 可以将分布式中不同的进程或服务串在一起,因为每条 Trace Log 中记录了 parent_span_id 和 span_id,通过它们之间的关系可以将一次请求所有的 RPC 调用组合成一棵树。但是仅仅通过 span_id 之间的关系来分析,在日志量巨大的情况下是非常耗时的,因此使用一个统一的 trace id (通常是64位随机数) 来标识一次请求,分布式系统对外的一次服务所有的 RPC 请求都对应一个 trace id,提高了日志的检索效率。
Sampling
trace id 另外一个用途是用来采样,将 trace id 哈希成一个 0 ≤ z ≤ 1 的值,同时设置一个全局的系数,当 z 小于这个系数时将 Trace Log 进行记录,否则滤掉。这就保证了分布式系统对外提供的每一次服务对应的不同 RPC 请求要么全部被记录,要么全部被过滤掉。
Blkin
确切来讲,blkin 自己并不能算是 Dapper 的开源实现,比如它没有收集日记的工具,而是借助 lttng 来将 Trace 写入日志文件并进行收集。
其跟 Dapper 相关的结构体列举如下:
/**
* @struct blkin_endpoint
* Information about an endpoint of our instrumented application where
* annotations take place
*/
struct blkin_endpoint {
const char *ip;
int16_t port;
const char *name;
};
/**
* @struct blkin_trace_info
* The information exchanged between different layers offering the needed
* trace semantics
*/
struct blkin_trace_info {
int64_t trace_id;
int64_t span_id;
int64_t parent_span_id;
};
/**
* @struct blkin_trace
* Struct used to define the context in which an annotation happens
*/
struct blkin_trace {
const char *name;
struct blkin_trace_info info;
const struct blkin_endpoint *endpoint;
};
/**
* @typedef blkin_annotation_type
* There are 2 kinds of annotation key-val and timestamp
*/
typedef enum {
ANNOT_STRING = 0,
ANNOT_INTEGER,
ANNOT_TIMESTAMP
} blkin_annotation_type;
/**
* @struct blkin_annotation
* Struct carrying information about an annotation. This information can either
* be key-val or that a specific event happened
*/
struct blkin_annotation {
blkin_annotation_type type;
const char *key;
union {
const char *val_str;
int64_t val_int;
};
const struct blkin_endpoint *endpoint;
};
Ceph 使用了 blkin 来做分布式跟踪,略。