OpenTracing 于 2016 年 10 月加入 CNCF 基金会,是继 Kubernetes 和 Prometheus 之后,第三个加入 CNCF 的开源项目。它是一个中立的(厂商无关、平台无关)分布式追踪的 API 规范,提供统一接口,可方便开发者在自己的服务中集成一种或多种分布式追踪的实现。本文讲一讲 OpenTracing 的来龙去脉,以及在容器化和微服务盛行的今天,为什么分布式追踪显得格外有用。

Distributed Tracing

什么是 Tracing

图片来源 Metrics, tracing, and logging

Wikipedia 中,对 Tracing 的定义 是,在软件工程中,Tracing 指使用特定的日志记录程序的执行信息,与之相近的还有两个概念,它们分别是 Logging 和 Metrics。

  • Logging:用于记录离散的事件,包含程序执行到某一点或某一阶段的详细信息。
  • Metrics:可聚合的数据,且通常是固定类型的时序数据,包括 Counter、Gauge、Histogram 等。
  • Tracing:记录单个请求的处理流程,其中包括服务调用和处理时长等信息。

同时这三种定义相交的情况也比较常见。

  • Logging & Metrics:可聚合的事件。例如分析某对象存储的 Nginx 日志,统计某段时间内
  • GET、PUT、DELETE、OPTIONS 操作的总数。 Metrics & Tracing:单个请求中的可计量数据。例如 SQL
  • 执行总时长、gRPC 调用总次数。 Tracing & Logging:请求阶段的标签数据。例如在 Tracing
    的信息中标记详细的错误原因。

针对每种分析需求,我们都有非常强大的集中式分析工具。

  • Logging:ELK,近几年势头最猛的日志分析服务,无须多言。
  • Metrics:Prometheus,第二个加入 CNCF 的开源项目,非常好用。
  • Tracing:OpenTracing 和 Jaeger,Jaeger 是 Uber 开源的一个兼容 OpenTracing 标准的分布式追踪服务。目前 Jaeger 也加入了 CNCF。

为什么需要 Distributed Tracing


图片来源 OpenTracing Joins the Cloud Native Computing Foundation

微服务极大地改变了软件的开发和交付模式,单体应用被拆分为多个微服务,单个服务的复杂度大幅降低,库之间的依赖也转变为服务之间的依赖。由此带来的问题是部署的粒度变得越来越细,众多服务给运维带来巨大压力,不过好在我们有 Kubernetes,可以解决大部分运维方面的难题。

随着服务数量的增多和内部调用链的复杂化,仅凭借日志和性能监控很难做到 “See the Whole Picture”,在进行问题排查或是性能分析的时候,无异于盲人摸象。分布式追踪能够帮助开发者直观分析请求链路,快速定位性能瓶颈,逐渐优化服务间依赖,也有助于开发者从更宏观的角度更好地理解整个分布式系统。

下面用 Jaeger 举一个小例子。

上图为 Jaeger 呈现的一个 HTTP 请求过程,无关名称已做模糊处理

乍看上去是不是有点火焰图的感觉,从 Jaeger 的前端界面上可以清晰的看到某个请求的所有阶段和内部调用,以及每个阶段所耗费的时间。展开某个阶段,还能看到这个阶段是在哪台机器(或容器)上执行的,也可以针对请求阶段增加的自定义标记,例如标记错误原因。之后还会单独写一篇关于 Jaeger 的具体实践文章,详细介绍一下如何将 Jaeger 集成到自己的服务当中。

原理

分布式追踪系统大体分为三个部分,数据采集、数据持久化、数据展示。数据采集是指在代码中埋点,设置请求中要上报的阶段,以及设置当前记录的阶段隶属于哪个上级阶段。数据持久化则是指将上报的数据落盘存储,例如 Jaeger 就支持多种存储后端,可选用 Cassandra 或者 Elasticsearch。数据展示则是前端根据 Trace ID 查询与之关联的请求阶段,并在界面上呈现。

图片来源 Introduction OpenTracing

上图是一个请求的流程例子,请求从客户端发出,到达负载均衡,再依次进行认证、计费,最后取到目标资源。

请求过程被采集之后,会以上图的形式呈现,横坐标是时间,圆角矩形是请求的执行的各个阶段。

OpenTracing

发展历史

早在 2005 年,Google 就在内部部署了一套分布式追踪系统 Dapper,并发表了一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,阐述了该分布式追踪系统的设计和实现,可以视为分布式追踪领域的鼻祖。随后出现了受此启发的开源实现,如 Zipkin、SourceGraph 开源的 Appdash、Red Hat 的 Hawkular APM、Uber 开源的 Jaeger 等。但各家的分布式追踪方案是互不兼容的,这才诞生了 OpenTracing。OpenTracing 是一个 Library,定义了一套通用的数据上报接口,要求各个分布式追踪系统都来实现这套接口。这样一来,应用程序只需要对接 OpenTracing,而无需关心后端采用的到底什么分布式追踪系统,因此开发者可以无缝切换分布式追踪系统,也使得在通用代码库增加对分布式追踪的支持成为可能。

图片来源 OpenTracing: Turning the Lights On for Microservices

目前,主流的分布式追踪实现基本都已经支持 OpenTracing,包括 Jaeger、Zipkin、Appdash 等,具体可参考官方文档 《Supported Tracer Implementations》。

数据模型
这部分在 OpenTracing 的规范中写的非常清楚,下面只大概翻译一下其中的关键部分,细节可参考原始文档 《The OpenTracing Semantic Specification》。

Causal relationships between Spans in a single Trace[Span A]  ←←←(the root span)|+------+------+|             |[Span B]      [Span C] ←←←(Span C is a `ChildOf` Span A)|             |[Span D]      +---+-------+|           |[Span E]    [Span F] >>> [Span G] >>> [Span H]↑↑↑(Span G `FollowsFrom` Span F)

Trace 是调用链,每个调用链由多个 Span 组成。Span 的单词含义是范围,可以理解为某个处理阶段。Span 和 Span 的关系称为 Reference。上图中,总共有标号为 A-H 的 8 个阶段。

Temporal relationships between Spans in a single Trace––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time[Span A···················································][Span B··············································][Span D··········································][Span C········································][Span E·······]        [Span F··] [Span G··] [Span H··]

上图是按照时间顺序呈现的调用链。

每个阶段(Span)包含如下状态:

  • 操作名称
  • 起始时间
  • 结束时间
  • 一组 KV 值,作为阶段的标签(Span Tags)
  • 阶段日志(Span Logs)
  • 阶段上下文(SpanContext),其中包含 Trace ID 和 Span ID
  • 引用关系(References)

阶段(Span)可以有 ChildOf 和 FollowsFrom 两种引用关系。ChildOf 用于表示父子关系,即在某个阶段中发生了另一个阶段,是最常见的阶段关系,典型的场景如调用 RPC 接口、执行 SQL、写数据。FollowsFrom 表示跟随关系,意为在某个阶段之后发生了另一个阶段,用来描述顺序执行关系。

如果对原理比较感兴趣,建议读一下 OpenTracing 的规范文档和 Go 语言的实现。

建议使用方式

首先假设某微服务已经有了中心化的日志收集和处理系统,如果还没有的话,强烈建议部署一套 ELK。再假设对于每一个请求,都会有一个贯穿整个请求流程的 Request ID,如果还没有的话,强烈建议加一个。以上准备完毕后,可以选取一个分布式追踪系统,集成到服务当中,建议采用 Jaeger。重点在最后,在 Trace 的起始处,将 Trace ID 设置为 Request ID,这么一来就打通了日志系统和分布式追踪系统,可以使用同一个 ID 查询请求的事件流和日志流,从此开启了上帝视角。

具体使用

脱离分布式追踪系统单独讲 OpenTracing 的使用方法的话,意义不大,所以本文就不介绍具体的使用方法,之后会以 Jaeger 为例,解释如何给微服务增加分布式追踪,以及如何与现有的日志系统集合。

如果想简单了解一下使用方式,可参考 OpenTracing 的《Quick Start》。

非入侵式

除了通过修改应用程序代码增加分布式追踪之外,还有一种不需要修改代码的非入侵的方式,那就是 Service Mesh。Service Mesh 一般会被翻译成服务啮合层,它是在网络层面做文章,通过 Sidecar 的方式为 Pod 增加一层代理,通过这层网络代理来实现一些服务治理的功能,因为是工作在网络层面,可以做到跨语言、非入侵。Istio 则是目前最成熟的 Service Mash 工具,支持启用分布式追踪服务。Istio 会修改微服务之间发送的网络请求,在请求中注入 Trace 和 Span 标记,再将采集到的数据发送到支持 OpenTracing 的分布式追踪服务中,从而拿到请求在微服务中的调用链。当然这种方式也有缺点,它无法追踪某个微服务内部的调用过程,并且目前阶段 Istio 只能追踪 HTTP 请求,能够覆盖的范围比较有限。如果想追踪更详细的数据,还是需要在中间件和代码中埋点,不过好在埋点的过程并不复杂,不会成为一个额外的负担。

参考资料

  • Datadog + OpenTracing: Embracing the open standard for APM https://www.datadoghq.com/blog/opentracing-datadog-cncf/
  • Metrics, tracing, and logging https://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html
  • Wikipedia - Tracing (software) https://www.wikiwand.com/en/Tracing_(software)
  • Elastic https://www.elastic.co
  • Prometheus https://prometheus.io
  • OpenTracing http://opentracing.io
  • Jaeger https://www.jaegertracing.io
  • OpenTracing Joins the Cloud Native Computing Foundation https://www.cncf.io/blog/2016/10/11/opentracing-joins-the-cloud-native-computing-foundation/
  • Introduction OpenTracing http://opentracing.io/documentation/
  • Dapper, a Large-Scale Distributed Systems Tracing Infrastructure https://ai.google/research/pubs/pub36356
  • OpenTracing: Turning the Lights On for Microservices https://www.cncf.io/blog/2016/10/20/opentracing-turning-the-lights-on-for-microservices/
  • Supported Tracer Implementations http://opentracing.io/documentation/pages/supported-tracers.html#supported-tracer-implementations
  • The OpenTracing Semantic Specification https://github.com/opentracing/specification/blob/master/specification.md
  • Istio https://istio.io

OpenTracing 详解相关推荐

  1. Gerber 格式详解

    Gerber 格式详解 gerber中文 gerber,gerber 文件:590m.com/f/25127180-487459253-79168e(访问密码:551685) 以下内容无关: ---- ...

  2. 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)

    首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...

  3. JVM年轻代,老年代,永久代详解​​​​​​​

    秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...

  4. docker常用命令详解

    docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...

  5. 通俗易懂word2vec详解词嵌入-深度学习

    https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...

  6. 深度学习优化函数详解(5)-- Nesterov accelerated gradient (NAG) 优化算法

    深度学习优化函数详解系列目录 深度学习优化函数详解(0)– 线性回归问题 深度学习优化函数详解(1)– Gradient Descent 梯度下降法 深度学习优化函数详解(2)– SGD 随机梯度下降 ...

  7. CUDA之nvidia-smi命令详解---gpu

    nvidia-smi是用来查看GPU使用情况的.我常用这个命令判断哪几块GPU空闲,但是最近的GPU使用状态让我很困惑,于是把nvidia-smi命令显示的GPU使用表中各个内容的具体含义解释一下. ...

  8. Bert代码详解(一)重点详细

    这是bert的pytorch版本(与tensorflow一样的,这个更简单些,这个看懂了,tf也能看懂),地址:https://github.com/huggingface/pytorch-pretr ...

  9. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

最新文章

  1. python urllib.request 爬虫 数据处理-运维学python之爬虫基础篇(二)urllib模块使用...
  2. Java 基础【08】.class getClass () forName() 详解
  3. linux误删视频恢复吗,linux 误删文件恢复
  4. OpenCASCADE:使用扩展数据交换 XDE之剪裁平面
  5. java线程并发库之--线程同步工具CountDownLatch用法
  6. 厉害了!地大这位29岁博导,最大的爱好是研究火……
  7. python输出文本内容_python 打印文件里的内容
  8. php区分全角半角字符,php如何判断是字符串全角还是半角
  9. 12月中国区块链经理人指数:环比出现大幅下跌 企业融资不理想
  10. 整理自己的.net工具库
  11. CPU 架构 —— ARM 架构
  12. 解决Ubuntu下任务栏不显示任务的问题
  13. java获取某年度有多少周_java获取一年共有多少周
  14. git报错 fatal: unsafe repository 解决方法 xxx is owned by someone else
  15. Maestro Z实时无标记细胞分析仪,评估免疫细胞治疗效价
  16. Windows自带虚拟化服务工具Hyper-V学习了解和实操
  17. 分布式数据库中间件 MyCat 搞起来!
  18. 华为OD机试真题 Python 实现【机器人】【100%通过率】【2022.11 Q4 新题】
  19. iOS Core Bluetooth_2 基础知识
  20. 挖洞实战之信息泄露与前端加密

热门文章

  1. python基本操作_python的基本操作
  2. Yapi 可视化接口管理平台部署文档
  3. adb 的批处理命令
  4. 4.9. 触发器(Trigger)
  5. 笨笨图片批量抓取下载 V0.2 beta[C# | WinForm | 正则表达式 | HttpWebRequest | Async异步编程]...
  6. Neo4j:入门基础(八)之Traversal API
  7. 信息系统项目管理师核心考点(五十四)配置项分类、状态与版本
  8. 三角形质心坐标怎么求_三角形的重心怎么求
  9. Linux电池电量信息读取,linux内核 – 如何在Linux内核模块中获取电池电量?
  10. 网络卡打开网页在转圈圈怎么解决?