在分布式追踪系统中使用 W3C Trace Context

https://dev.to/luizhlelis/using-w3c-trace-context-standard-in-distributed-tracing-3743

在软件开发中,当系统遭遇到运行时失效的时刻,开发人员会本能地尝试找到是哪里调用了失效的方法,以及哪里是原始的请求。这就是 stack trace 的作用,比如下面的示例所示。

Unhandled exception. System.InvalidOperationException: Stack trace example
at Program.CallChildActivity() in /Users/luizhlelis/Documents/projects/personal/trace-context-w3c/src/system-diagnostics-activity/Program.cs:line 22
at Program.Main() in /Users/luizhlelis/Documents/projects/personal/trace-context-w3c/src/system-diagnostics-activity/Program.cs:line 11

基于上面的信息,我们就可以直到失效发生在 CallChildActivity() 方法 ( 22 行 ),它是被 Main() 方法 ( 1 行 ) 所调用,它们都位于 Program.cs 类中。这就是运行时消息追踪对于软件的健康和可信赖如此重要的原因。像这样丰富的信息极大提高了解决问题的生产力。所以,用术语消息追踪来说,stack trace 对于目标是单进程的应用程序来说非常适合,比如单体应用系统。但是反过来说,对于处理分布式应用系统,例如微服务架构,stack trace 就不能足够用来展示整体的消息追踪了。这就是为什么分布式追踪工具和标准变得必要的原因。W3C 定义了这种追踪类型的标准,称为 Trace Context

W3C Trace Context 目标

想象一个使用微服务架构设计的系统,它提供 2 个使用同步方式通讯的 API,其中的第 2 个与 worker 通过消息代理通讯。

图 1 分布式追踪

stack trace 类似,每个 Activity 需要一个唯一标识,还需要知道是调用者的唯一标识。为了解决此类问题,许多厂商发布了不仅提供分布式追踪消息信息,还包括了应用程序性能,加载时间,应用程序响应时间,以及其它内容。此类 vendor 被称为 应用程序性能管理工具 ( Application Performance Management tools (APM tools) ),或者追踪系统,下面是其中的一些:

  • Dynatrace
  • New Relic
  • Application Insights
  • Elastic APM
  • Zipkin

注意:我选择术语 verdor 来描述所有的追踪系统,是因为这是标准的说明它们的方式。但是看起来 它会很快发生变化

现在想象一个场景,这里有各种 vendor 使用各种语言并使用各种的诊断库,有一些使用 operation-id 来标识,有些使用 request-id,可能还有一些使用 trace-id。除此之外,基于不同 vendor 或者诊断库的标识格式也各不相同。有的是分层 ( hierarchical ) 格式,有的使用 UUID,有的是 24 字符的字符串格式等等。这就会导致这样的结果:使用不同追踪系统 vendor 导致不能关联起来,也不能将追踪传播,因为这里没有唯一标识可以传递。这就是 trace context 标准的作用。

trace context 标准

W3C Trace Context 规范定义了针对 HTTP 头的标准和格式,用来传播分布式追踪上下文信息。其中定义了 2 个字段用来在 HTTP 请求头中传播追踪流。先看一下标准定义中的这 2 个字段:

  • traceparent: 用来描述在追踪图谱中到达请求的位置。它表示在追踪系统中到达请求的通用格式,被所有的 vendor 所理解。
  • tracestate: 使用 vendor 特定的数据表示形式来扩展 traceparent,使用 name/value 对形式。在 tracestate 中保存信息是可选的。

traceparent 字段

traceparent 字段的规范使用扩充巴科斯范式 (ABNF ) 形式定义,由 4 个部分组成

version - traceid - parentid/spanid - traceflags

注意:sub-field 术语是非官方的。我使用该术语仅仅用于说明。

例如:

00-480e22a2781fe54d992d878662248d94-b4b37b64bb3f6141-00
  • version: 8 位,系统适配的追踪上下文版本,当前位 00
  • trace-id: 16 字节,追踪整体的标识。用于在系统中标识一个分布式追踪整体。
  • parent-id/span-id: 8 字节,用来表述在进入请求中,或者对外请求中,当前跨度的父级。
  • trace-flags: 8 位,调用者的建议标志,可以考虑为调用者的建议,限制为 3 个原因:信息或是滥用,调用方的错误,或者在调用方与被调用方的不同负载。

所有字段都使用 16 进制编码 ( hexadecimal )

进而,在图 1 中的应用程序中应用 trace context 的概念,将导致如下的结果:

图 2 传播字段

需要注意的是,trace-id 标识了整个追踪,而 parent-id 标识整个追踪中限定的范围。进而,traceparenttracestate 一起在整个追踪流中传播。

为了更好地动态说明 traceparent,让我们看下面的示例,它使用 C# 编写,这里生成了 2 个跨度,并且共享的上下文在其间传播。

using System;
using System.Diagnostics; var upstreamActivity = new Activity("Upstream"); upstreamActivity.Start();
Console.WriteLine(upstreamActivity.OperationName);
Console.WriteLine("traceparent: {0}", upstreamActivity.Id);
CallChildActivity();
upstreamActivity.Stop(); Console.ReadKey(); void CallChildActivity()
{
var downstreamActivity = new Activity("Downstream Dependency"); downstreamActivity.Start();
Console.WriteLine(downstreamActivity.OperationName);
Console.WriteLine("traceparent: {0}", downstreamActivity.Id);
downstreamActivity.Stop();
}

注意:在 .NET 5 中,System.Diagnostics.Activity 库已经被配置为使用 W3C 标准。

即使上面的示例是作为单进程应用程序,还是使用了 Trace Context 标准的模式。基本上,这个程序做这些事情:

  • 首先,它开始一个上游的跨度,并输出其 traceparent 到控制台
  • 然后,它调用一个下游的方法,开始另一个跨度,也输出它的 traceparent 到控制台,并关闭跨度
  • 最后,上游的跨度被关闭

输出如下所示:

Upstream
traceparent: 00-3e425f2373d89640bde06e8285e7bf88-9a5fdefae3abb440-00 Downstream Dependency
traceparent: 00-3e425f2373d89640bde06e8285e7bf88-0767a6c6c1240f47-00

注意这个 trace-id (3e425f2373d89640bde06e8285e7bf88) 在整个追踪中被维护,而 parent-id 基于不同的跨度是不同的,上游中是:9a5fdefae3abb440 而下游中是 0767a6c6c1240f47。

在有些场景下,parent-id 会由于其名称导致困惑。但是,该名称是相对于到达的请求来说的。因此,必须从端点的角度来看待,例如,考虑一个请求消息刚刚到达 API 的控制器,从请求头中接收到的 traceparent 还没有被更新到中间件跨度的 parent-id 中,所以,此刻 traceparent中的 parent-id 就是上游标识,或者说,就是父级。

tracestate 字段

Trace Context:AMQP 协议

如图 2 所示,在微服务架构中,通常使用中间商来传播消息。对于此类操作,有另一个文档规范该模式 ( 这里使用 AMQP 协议 ),Trace Context: AMQP protocol

Trace Context: AMQP 协议 是另外一个 W3C 示例文档,该规范定义了与 HTTP 标准不同的 trace context 字段处理。

该标准建议 traceparenttracestat 两者应该添加到消息发布者的消息的 application-properties 部分中,从消息读取者的角度来说,trace context 应该首先通过读取 message-annotations 来构建,如果这里不存在,再通过 application-properties 读取。参见如下的 AMQP 协议消息格式。

图 3 AMQP 消息格式

将 trace context 字段放置到消息发布者定义的消息内的 application-properties 部分的原因是中间商不能修改这些属性,因为这部分是不可变的。从另外的角度来说,message-annotations 被设计为由中间商使用,换句话说,该部分中的字段可以在消息处理过程中发生更改。因此,这意味着,如果需要在中间件内部对消息进行注释,则必须在消息注释部分中进行注释,并使用发布者在应用程序属性中发送的字段作为基础。

小结

W3C 标准规范了在分布式追踪系统中的模式。当前,只有用于 HTTP 的,其它还在工作中 ( AMQP, MQTT 和 baggate)。但这不意味着你应该在产品环境中忽视它,但是要注意到这些变化,更重要的是保持对最新发布的更新。

在分布式追踪系统中使用 W3C Trace Context的更多相关文章

  1. Uber分布式追踪系统Jaeger使用介绍和案例

    原文:Uber分布式追踪系统Jaeger使用介绍和案例[PHP Hprose Go] 前言   随着公司的发展,业务不断增加,模块不断拆分,系统间业务调用变得越复杂,对定位线上故障带来很大困难.整个调 ...

  2. 开源分布式追踪系统 — Jaeger介绍

    目录 一.Jaeger是什么 二.Jaeger架构 1. 术语 2. 架构图 三.关于采样率 四.部署与实践 一.Jaeger是什么 Uber开发的一个受Dapper和Zipkin启发的分布式跟踪系统 ...

  3. [业界方案] 用SOFATracer学习分布式追踪系统Opentracing

    [业界方案] 用SOFATracer学习分布式追踪系统Opentracing 目录 [业界方案] 用SOFATracer学习分布式追踪系统Opentracing 0x00 摘要 0x01 缘由 &am ...

  4. [业界方案]用Jaeger来学习分布式追踪系统Opentracing

    [业界方案]用Jaeger来学习分布式追踪系统Opentracing 目录 [业界方案]用Jaeger来学习分布式追踪系统Opentracing 0x00 摘要 0x01 缘由 & 问题 1. ...

  5. 分布式追踪系统dapper

    http://www.cnblogs.com/LBSer/p/3390852.html 最近单位需要做自己的分布式监控系统,因此看了一些资料,其中就有google的分布式追踪系统dapper的论文:h ...

  6. Linux下安装 SkyWalking 分布式追踪系统

    Linux下安装 SkyWalking 分布式追踪系统 1.SkyWalking简介 1.1 SkyWalking介绍 SkyWalking项目是由华为大牛吴晟开源的个人项目,目前已经加入Apache ...

  7. SkyWalking 分布式追踪系统

    随着微服务架构的流行,一些微服务架构下的问题也会越来越突出,比如一个请求会涉及多个服务,而服务本身可能也会依赖其他服务,整个请求路径就构成了一个网状的调用链,而在整个调用链中一旦某个节点发生异常,整个 ...

  8. .NetCore从零开始使用Skywalking分布式追踪系统

    本文将从0开妈搭建两个webapi项目,使用Skywalking来追踪他们之间的调用关系及响应时间.开发环境为VisualStudio2019 1:安装Skywalking,可参考:https://w ...

  9. 架构设计 | 分布式业务系统中,全局ID生成策略

    本文源码:GitHub·点这里 || GitEE·点这里 一.全局ID简介 在实际的开发中,几乎所有的业务场景产生的数据,都需要一个唯一ID作为核心标识,用来流程化管理.比如常见的: 订单:order ...

  10. Docker安装Skywalking APM分布式追踪系统

    环境介绍 本文使用虚拟机unbutu18+docker.本unbutu18系统IP地址为:192.168.150.134 大家在使用时记得将此地址换成自己的实际地址. docker的安装可参考:htt ...

随机推荐

  1. WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!

    前言 今天大姚给大家分享一套基于.NET 8.0 + LayUI的快速开发框架,项目完全开源.免费(MIT License)且开箱即用:WaterCloud. 可完全实现二次开发让开发更多关注业务逻辑 ...

  2. 配置windows update失败还原更改

    配置windows update失败还原更改_解决方案 解决方法: 方法1:     重启,按F8,选择最后一次正常启动.     如果还是需要等待.可采用方法2: 方法2:     重启,按F8,选 ...

  3. JVM--解析运行期优化与JIT编译器

    JVM开发团队一直在努力,缩小Java与C/C++语言在运行效率上的差距. 本篇博客,我们来谈一谈JVM(HotSpot)为了提高Java程序的运行效率,都实现了哪些激动人心的技术- 1 JIT编译器 ...

  4. 使用Redis的好处

    性能极高--redis能支持超过100K+每秒的读写频率 丰富的数据类型--Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型 ...

  5. 在 Ubuntu 22.04 上安装 KubeSphere 实战教程

    作者:老 Z,中电信数智科技有限公司山东分公司运维架构师,云原生爱好者,目前专注于云原生运维,云原生领域技术栈涉及 Kubernetes.KubeSphere.DevOps.OpenStack.Ans ...

  6. 如何在 ubuntu 上搭建 minio

    由于腾讯的对象存储服务器(COS)的半年免费试用期已过,所以寻思鼓捣一下 minio,试着在自己的服务器上搭建一套开源的 minio 对象存储系统. 单机部署基本上有以下两种方式. 直接安装 最基础的 ...

  7. CF1737D Ela and the Wiring Wizard

    CF1737D Ela and the Wiring Wizard 题意简述 形象化的,对于一个边,我们可以做以下变换: 将一条边变为自环 将边的一个端点沿着其他边移动 总的来说,就是边的两个端点可以 ...

  8. vue3 使用swiper轮播组件

    本地环境信息 node版本: nodejs : v18.20.4 npm : 10.7.0 vue版本 "dependencies": { "vue": &qu ...

  9. 洛谷 P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布

    题目大意 小A和小B,要进行 \(N\) 次猜拳,每次按照一定周期出拳,胜负情况如下: 求出小A和小B分别赢了几次. 思路 枚举 \(N\) 次猜拳,每次比较 \(a[powera]\) 与 \(b[ ...

  10. mysql替换内容

    UPDATE storage SET guige = REPLACE(guige, '×', 'x')