OpenTelemetry初识及调用链Trace详解

目录
  • 前言
  • 初识OpenTelemetry
  • 调用链Trace
    • Span
      • Span Context
      • Attributes
      • Span事件
      • Span Links
      • Span状态
      • Span Kind
    • Trace构建的原理
  • Metrics
  • Logs
  • Baggage
  • 总结

前言

OpenTelemetry作为一个分布式追踪的项目,他支持非常多的语言,如Java,Golang,Python等,鉴于笔者的主力语言为Java,并且后续需要介绍OpenTelemetry的Java Agent实现,所以后续文章中的相关知识点都以Java或者Java Sdk的方式为主。

初识OpenTelemetry

在微服务广泛发展和使用的当下,对于整个微服务体系的使用情况的观察以及服务依赖调用情况都不再像以往那么清晰明了。而这正是OpenTelemetry能够为我们提供的能力。

OpenTelemetry源自OpenSencuc和OpenTracing的合并,它的目标是集成Trace,Metrics,Logging能力来提供可观测性。过去的分布式追踪往往是各做各的,没有固定的标准,各个分布式追踪方案各显神通,使用不同的协议,不同的标准。但是OpenTelemetry不同,它提供了一系列的标准,并且他的可插拔式的架构为将来的协议和数据结构扩展提供了便利的方式。

调用链Trace

分布式调用链,俗称调用链,用来记录请求的路径整体路径。下图是一个典型的的请求以及其RPC调用的链路:

从图中我们可以很清晰的了解到刚才的请求是怎么一个流转过程,经过了什么组件和服务,接口。这就是调用链的作用之一,让我们的请求链路更加透明清晰。

Span

Span在调用链中是一个基础的单元,一个调用链是由很多的Span组成的。在一个Span中会包含如下信息:

  • 名称
  • 父Span的ID,root节点的父Span为空
  • 开始与结束时间戳
  • Span Context
  • Attributes
  • Span事件
  • Span Links
  • Span状态
  • Span Kind

以下是一个典型的Span结构:

{
  "trace_id": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
  "parent_id": "",
  "span_id": "086e83747d0e381e",
  "name": "/v1/sys/health",
  "start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
  "end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
  "status_code": "STATUS_CODE_OK",
  "status_message": "",
  "attributes": {
    "net.transport": "IP.TCP",
    "net.peer.ip": "172.17.0.1",
    "net.peer.port": "51820",
    "net.host.ip": "10.177.2.152",
    "net.host.port": "26040",
    "http.method": "GET",
    "http.target": "/v1/sys/health",
    "http.server_name": "mortar-gateway",
    "http.route": "/v1/sys/health",
    "http.user_agent": "Consul Health Check",
    "http.scheme": "http",
    "http.host": "10.177.2.152:26040",
    "http.flavor": "1.1"
  },
  "events": [
    {
      "name": "",
      "message": "OK",
      "timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
    }
  ]
}

Span Context

Span Context可以理解为上下文,是Span中包含的不可变的对象。在Span Context中包含了:

  • traceId:调用链ID
  • spanId:Span的ID
  • traceFlag:二进制形式的调用链标志位,一般用于表示调用链是否采样(isSampled)
  • traceState:承载调用链信息的K-V结构列表

Attributes

Attributes是一个用来携带信息的K-V结构。

在java sdk中可以通过:

Span.current().setAttribute("My Attributes", "attr");

来自定义你想要设置的Attributes。当然在OpenTelemetry中默认内置的那些Instrumentation都会有定义一些指定标准化的的Attributes,详情可以参照Semantic Attributes

Span事件

Span事件(Events)是一种事件机制,可以将事件触发与具体的Span进行绑定,然后在调用链页面展示出来。如下事例:

Span.current().addEvent("My Event");

Span Links

Span Links是一种能够将调用链关联起来的技术,通过配置关联的Span,可以在页面中展现关联的调用链信息。不过请注意Span Links必须要在Span创建时才能添加,不像Events和Attributes一样能在Span创建之后添加。例子如下:

Tracer tracer = GlobalOpenTelemetry.getTracer("1111");
Span span = tracer.spanBuilder("start")
        .addLink(SpanContext.create("ee868088dfd10adbaa459c9aa353b112", "53b11b6c55010604",
                TraceFlags.getDefault(), TraceState.getDefault())).startSpan();
span.end();

Span状态

Span状态(Status)是定义好的Span的状态,有如下几种:

  • Unset
  • Ok
  • Error

Span Kind

Span Kind是指Span类型,有如下几种:

  • Server
  • Client
  • Producer
  • Consumer
  • Internal

顾名思义Server/Client指的是服务端/客户端,Producer/Consumer指的是生产者/消费者,显然这个一般适用于消息队列,Internal是内部组件产生的Span

Trace构建的原理

简单来说的话Trace是由众多的Span组成的,而Span则是由众多的Instrumentation库组成的,这些库由开源作者构建,用于支持不同的组件,如http请求,kafka,redis等等。依托于这些Instrumentation,调用链可以生成对应的Span。

生成Span自然不是难题,问题在于是如何将这些Span串联起来的。在Trace中有一个唯一的标识TraceID,而且在Span中也有一个SpanId和ParentSpanId,借助这些信息,在Span将所有数据推送到服务端后,服务端就能根据这些信息进行重组,然后在界面上进行展示。

但是又存在一个问题,TraceId以及ParentSpanId是如何在Span间进行传递的呢?

这里就涉及到了Trace的底层原理了。在这里以Java Sdk来举例。在Sdk中会定义一个Context类用于建立一个内存中的线程隔离的存储机制来存储上游传递的数据。一般来说上游往下游传递数据每个插件都是不同的形式。例如如果是http请求,那就借助Header,如果是Kafka,也是借助于Kafka自带的prop来进行数据传递。之后在下游获取到数据后利用Context将其存放入内存中,这个过程被称为extract,在数据要再往下传递时,需要将内存中数据取出,在解析成Header或是其他的形式,这个被称为inject。调用链信息正是以此来传递的。

Trace就是依靠traceparent来进行传递的,traceparent不仅包含了traceId,还包含了一些isSample等等的基础信息。

Metrics

Metrics是一种度量标准,用于展现应用的CPU,内存等等指标级的度量信息。

OpenTelemetry定义了三种metrics仪器:

  • counter: 累加值,这类指标不会减少,只会不断的累加上去
  • measure: 一段时间的数据聚合值,表示的是一段时间内的数据累加值
  • observer: 抓取当前时间的一系列特定值

实际上OpenTelemetry提供了许多基础的指标计算方式,例如:LongCounter,LongUpDownCounter,DoubleHistogram,DoubleGauge等等。

Meter meter = GlobalOpenTelemetry.meterBuilder("my-meter-instrumentation")
                .setInstrumentationVersion("1.0.0")
                .build();
LongCounter counter = meter
        .counterBuilder("my_metrics")
        .setDescription("My Metrics")
        .setUnit("1")
        .build();
counter.add(100);

上述代码是一个简单的创建指标的的例子,这里创建了一个固定值为100的名为my_metrics的指标,由于是counter,所以最终指标名为my_metrics_total

Logs

日志也是OpenTelemetry的一大功能之一,不过截止到本文发布前,Logs功能还未GA,因此存在变数,后续我们在聊到Agent相关内容时会再简单聊聊这部分内容,在这里就先一笔带过。

Baggage

Baggage用于在Span间传递数据。

设想一个场景,你希望在链路的当前的Span中将某些数据传递下去,使用attributes显示然是不行的,因此需要一些手段将其传递下去,Baggage就是为此而设计的。

其实Baggage的原理基本和调用链的traceId的传递基本相似,不同之处是它定义了一个名为baggage的key,而这个key中包含的值是以K-V形式组织的,因此你可以传递自己想要的值下去。

在早期Baggage底层维护了一个Map来存储这些数据,后来在某个版本后改成了用数组的形式,每两个数组位置分别存储一对K-V,并且做了一些特殊的处理来实现删除等操作,有兴趣的可以去看看源码。

总结

在本文中我们简单的介绍了OpenTelemetry的一些使用和实现的原理,在后续的文章中会更多的介绍整个OpenTelemetry的体系,请期待后续!

参考文档:

[1] opentelemetry.io/docs

以上就是OpenTelemetry初识及调用链Trace详解的详细内容,更多关于OpenTelemetry Trace调用链的资料请关注我们其它相关文章!

(0)

相关推荐

  • node故障定位顶级技巧动态追踪Dynamic Trace详解

    目录 背景和行文目的 动态追踪技术 是什么 优势 原理 用法 demo 演示 实战演示 搭建 easy-monitor 环境 启动一个 egg 应用 制造问题 Dynamic trace 精准定位 实战总结 分享代码 动态追踪技术的未来 传统工具 潜力工具 未来 + 顶尖 总结 背景和行文目的 在做 node 或者其他语言的软件开发时,是否有以下经历: 测试环境一切正常,发到生产环境后,出现诡异问题且难以定位 不同机器.不同容器上,某些逻辑呈现不同的结果,如时区. host 对于时好时坏的玄学问

  • 全局请求添加TraceId轻松看日志

    目录 引言 请求拦截器 统一返回值 日志配置 测试 异步调用配置 引言 不知道大家有没有一堆日志就是定位不到那块是异常部分,接口错误无法复现,也找不到报错信息等比较棘手的问题. 其实解决上面的问题很简单,只要我们为每一个请求都分配一个唯一的 RequestId 或者叫 TraceId ,一旦出了问题,只需要拿着 Id 去日志里一搜,妖魔鬼怪立马原形毕露. 对于分布式链路追踪,有很多开源中间件,本文主要通过 logback 的 MDC 实现. 请求拦截器 @Component public cla

  • 详解Opentelemetry Collector采集器

    目录 前言 客户端数据上报 OTLP OTLP/HTTP OTLP/gRPC Collector Collector简介 Collector使用 Receiver Processor Exportor Extension Service 个性化的Collector 总结 前言 上个篇章中我们主要介绍了OpenTelemetry的客户端的一些数据生成方式,但是客户端的数据最终还是要发送到服务端来进行统一的采集整合,这样才能看到完整的调用链,metrics等信息.因此在这个篇章中会主要介绍服务端的采

  • OpenTelemetry-go的SDK使用方法详解

    目录 例子 原理 方法使用 newExporter newResource trace.NewTracerProvider otel 注意 获取当前跨度 设置span状态 设置span属性 记录错误 设置活动 tp.Shutdown 2019年5月,OpenCensus 和 OpenTracing形成了 OpenTelemetry(简称 OTel) 也就是说,我们在使用链路追踪SDK的时候就需要使用OpenTelemetry的新规范.OpenTelemetry帮我们实现了相应语言的SDK,所以我

  • 功能强大的TraceId 搭配 ELK使用详解

    目录 引言 需求分析 ES kibana Logstash Logback Filebeat 最后 引言 之前写了一篇关于 TraceId 的文章:为全局请求添加 TraceId ,看日志再也不懵逼 今天就接着 TraceId 做一些优化,如果想快速的定位到问题,就要实现对日志的快速搜索,所以本文就引入 ELK 技术栈. ELK 是 ES.Logstash.Kibana 的总称,其核心功能就是实现数据的收集.搜索.可视化.具体功能和使用在本文都会提到. 需求分析 先分析一下,我们想实现的核心功能

  • OpenTelemetry初识及调用链Trace详解

    目录 前言 初识OpenTelemetry 调用链Trace Span Span Context Attributes Span事件 Span Links Span状态 Span Kind Trace构建的原理 Metrics Logs Baggage 总结 前言 OpenTelemetry作为一个分布式追踪的项目,他支持非常多的语言,如Java,Golang,Python等,鉴于笔者的主力语言为Java,并且后续需要介绍OpenTelemetry的Java Agent实现,所以后续文章中的相关

  • web3.js调用链上的方法操作NFT区块链MetaMask详解

    目录 实例化链上方法 MetaMask 首先要初始化web3 实例化链 调用链上方法授权 调用游戏链上方法质押NFT 实例化链上方法 公司的项目全是区块链项目,最近这个项目是要构建一个链上的游戏社区,目前这个功能是用户可以质押NFT到游戏的链上,然后游戏那边就可以有人去参加竞赛,然后质押人可以赎回NFT. MetaMask web3.js MetaMask 浏览器插件用的是小狐狸MetaMask 网络用的是测试网络Rinkeby,记得切换网络,把设置 > 高级 > 显示测试网络 打开 let

  • Java 异常的栈轨迹(Stack Trace)详解及实例代码

    Java 异常的栈轨迹(Stack Trace)详解 捕获到异常时,往往需要进行一些处理.比较简单直接的方式就是打印异常栈轨迹Stack Trace.说起栈轨迹,可能很多人和我一样,第一反应就是printStackTrace()方法.其实除了这个方法,还有一些别的内容也是和栈轨迹有关的. 1.printStackTrace() 首先需要明确,这个方法并不是来自于Exception类.Exception类本身除了定义了几个构造器之外,所有的方法都是从其父类继承过来的.而和异常相关的方法都是从jav

  • JavaScript原型继承和原型链原理详解

    这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性副本,又能共享同一个方法,这样的好处就是可以极大的节省内存空间.同时还可以向构造函数传递参数,十分的方便. 这里还要再讲一下两种特色的构造

  • Java设计模式之职责链模式详解

    目录 前言 一.职责链模式的定义与特点 二.职责链模式的结构 三.职责链模式案例 前言 本文简单介绍了设计模式的一种--职责链模式  一.职责链模式的定义与特点 定义: 为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链:当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止. 比如我们的审批制度,低等级的审批不了的,交给上一级审批,依次类推,直到审批结束. 在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处

  • Java设计模式中责任链模式详解

    目录 1.责任链设计模式的定义 2.责任链设计模式的优点与不足 3.责任链设计模式的实现思路 4.责任链设计模式应用实例 5.责任链设计模式应用场景 编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观. 在现实生活中,一个事件需要经过多个对象处理是很常见的场景.例如,采购审批流程.请假流程等.公司员工请假,可批假的领导有部门负责人.副总经理.总经理等,但每个领导能批准的天数不同,员工必须根据需要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名.电话

  • 微信小程序本作用域下调用全局JS详解及实例

    微信小程序本作用域下调用全局JS详解 本地wxml文件 <view> app版本:{{version}} </view> 本地js文件 var app; Page({ data:{ }, onLoad:function() { app = getApp(); this.setData({version:app.globalData.appName}); } }) 全局js文件 //app.js App({ globalData:{ appName:"hcoder"

  • Python 调用Java实例详解

    Python 调用Java实例详解 前言: Python 对服务器端编程不如Java 所以这方面可能要调用Java代码 前提: Linux 环境  1 安装 jpype1 安装后测试代码: from jpype import * startJVM(getDefaultJVMPath(), "-ea") java.lang.System.out.println("Hello World") shutdownJVM() 2 调用非jdk的jar包, test.jar 包

  • COM组件中调用JavaScript函数详解及实例

    COM组件中调用JavaScript函数详解及实例 要求是很简单的,即有COM组件A在IE中运行,使用JavaScript(JS)调用A的方法longCalc(),该方法是一个耗时的操作,要求通知IE当前的进度.这就要求使用回调函数,设其名称为scriptCallbackFunc.实现这个技术很简单: 1 .组件方(C++) 组件A 的方法在IDL中定义: [id(2)] HRESULT longCalc([in] DOUBLE v1, [in] DOUBLE v2, [in, optional

随机推荐