前语

分布式链路追寻的客户端完成中,咱们会通过各种手段和规则得到一个又一个的Span,得到这些Span后,需要在分布式链路追寻的服务端这边汇总这些Span并拼接出一条恳求链路,那么这儿就存在一个问题,客户端得到的Span如何给到服务端,通常是会在每个Span调用finish() 方法时将Span发送给服务端,这儿的发送有多种形式,例如把Span主动的pushKafkaTopic,还例如把Span当作一条日志打印出来再由Filebeat采集,咱们的本系列文章中,就选择将Span链路日志的形式打印出来,至于如何采集以及服务端如何拼接,这不在本系列文章的评论范围内。

正文

这儿直接给出界说好的链路日志格式,如下所示。

{
    "traceId": "testTraceId", // 当时节点所属链路的Id
    "spanId": "testSpanId", // 当时节点的SpanId
    "parentSpanId": "testparentSpanId", // 当时节点的父节点的SpanId
    "timestamp": "1704038400000", // 接收到恳求那一刻的毫秒时刻戳
    "duration": "10", // 表明接收恳求到响应恳求的耗时
    "httpCode": "200", // 恳求的HTTP状况码
    "host": "127.0.0.1", // 当时节点的主机地址
    "requestStacks": [ // 恳求堆栈
        {
            "subSpanId": "testSubSpanId", // 当时节点的子节点的SpanId
            "subHttpCode": "200", // 恳求子节点的HTTP状况码
            "subTimestamp": "1704038401000", // 当时节点恳求子节点的毫秒时刻戳
            "subDuration": "5", // 表明建议恳求到收到响应的耗时
            "subHost": "192.168.10.5", // 当时节点的子节点的主机地址
        }
    ]
}

特别阐明一下requestStacks这个字段,该字段首要便是用于记载当时节点调用下游子节点的Span的信息,包含子节点的SpanId,调用子节点得到的HTTP状况码和调用耗时等。

既然确认了链路日志的格式,现在咱们用一个示例demo,来结合链路日志做一个演示阐明。示例demo的调用链路如下所示。

3. 分布式链路追寻的链路日志规划

假定恳求在网络中跑不耗时,clientserver1的应用本身逻辑处理不耗时,那么关于client,打印的链路日志如下。

{
    "traceId": "0001",
    "spanId": "01",
    "parentSpanId": "0",
    "timestamp": "1704038400000",
    "duration": "100",
    "httpCode": "200",
    "host": "192.168.10.1",
    "requestStacks": [
        {
            "subSpanId": "02",
            "subHttpCode": "200",
            "subTimestamp": "1704038400000",
            "subDuration": "40",
            "subHost": "192.168.10.2"
        },
        {
            "subSpanId": "04",
            "subHttpCode": "200",
            "subTimestamp": "1704038400040",
            "subDuration": "60",
            "subHost": "192.168.10.3"
        }
    ]
}

关于server1,打印链路日志如下。

{
    "traceId": "0001",
    "spanId": "02",
    "parentSpanId": "01",
    "timestamp": "1704038400000",
    "duration": "40",
    "httpCode": "200",
    "host": "192.168.10.2",
    "requestStacks": [
        {
            "subSpanId": "03",
            "subHttpCode": "200",
            "subTimestamp": "1704038400000",
            "subDuration": "40",
            "subHost": "192.168.10.4"
        }
    ]
}

关于server2,打印链路日志如下。

{
    "traceId": "0001",
    "spanId": "04",
    "parentSpanId": "01",
    "timestamp": "1704038400040",
    "duration": "60",
    "httpCode": "200",
    "host": "192.168.10.3",
    "requestStacks": []
}

关于server3,打印链路日志如下。

{
    "traceId": "0001",
    "spanId": "03",
    "parentSpanId": "02",
    "timestamp": "1704038400000",
    "duration": "40",
    "httpCode": "200",
    "host": "192.168.10.4",
    "requestStacks": []
}

总结

其实打印链路日志,其中心目的便是记载每个SpantraceIdspanIdparentSpanId,通过这三个字段信息,就可以拼接出一条链路。此外,还可以根据实践的需求增加一些额外字段,例如和时刻相关的durationtimestamp,这两个字段能够协助排查链路中的耗时情况。