本次分享OpenTracing目的:

通过本次分享,你可以快速的上手使用OpenTracing,部署链路追踪到你的系统,但是你只能简单的认识它,并掌握如何使用,而它的实现原理是无法通过本次分享掌握的。

将通过以下几点来介绍OpenTracing

1.什么是链路追踪 ?

2.OpenTracing 是什么 ?

3.OpenTracing 的主要几个数据模型

4.基于jaegertracing 实现全链路追踪

5.如何查看追踪信息查看 ?

1.什么是链路追踪 ?

在微服务架构的系统中,请求在各服务之间流转,调用链错综复杂,一旦出现了问题和异常,很难追查定位,这个时候就需要链路追踪来帮忙了。链路追踪系统能追踪并记录请求在系统中的调用顺序,调用时间等一系列关键信息,从而帮助我们定位异常服务和发现性能瓶颈。

目前由各大互联网公司和开源社区开发的分布式链路追踪产品有很多,同时也给使用者带来了一个问题,各个分布式链路追踪产品的 API 并不兼容,如果用户在各个产品之间进行切换,成本非常高。而 OpenTracing 就完美的解决了这个问题,OpenTracing 通过提供平台无关、厂商无关的 API,帮助开发人员能够方便地添加(或更换)追踪系统。

2.OpenTracing是什么?

OpenTracing 是分布式链路追踪的一种规范标准,是CNCF(云原生计算基金会)下的项目之一。和一般的规范标准不同,OpenTracing 不是传输协议,消息格式层面上的规范标准,而是一种语言层面上的API标准。无论使用什么开发语言,只要某链路追踪系统实现了OpenTracing 规定的接口(interface),符合OpenTracing 定义的表现行为,那么就可以说该应用符合OpenTracing 标准。这意味着开发者只需修改少量的配置代码,就可以在符合OpenTracing 标准的链路追踪系统之间自由切换。

OpenTracing 对各种语言的支持:

  • Go - opentracing-go
  • Python - opentracing-python
  • Javascript - opentracing-javascript
  • Java - opentracing-java
  • C# - opentracing-csharp
  • Objective-C - opentracing-objc
  • C++ - opentracing-cpp
  • Ruby - opentracing-ruby
  • PHP - opentracing-php

3.OpenTracing 的主要几个数据模型

在使用Opentracing来实现全链路追踪前,有必要先了解一下它所定义的数据模型。

Span

Span是一条追踪链路中的基本组成要素,一个span表示一个独立的工作单元,比如可以表示一次函数调用,一次http请求等等。span会记录如下基本要素:

  • 服务名称(operation name)
  • 服务的开始时间和结束时间
  • K/V形式的Tags
  • K/V形式的Logs
  • SpanContext
  • References:该span对一个或多个span的引用(通过引用SpanContext)。

Tags

Tags以K/V键值对的形式保存用户自定义标签,主要用于链路追踪结果的查询过滤。例如: http.method="GET",http.status_code=200。其中key值必须为字符串,value必须是字符串,布尔型或者数值型。 span中的tag仅自己可见,不会随着 SpanContext传递给后续span。

例如:

span.SetTag(“http.method”,“GET”)
span.SetTag(“http.status_code”,200)

Logs

Logs与tags类似,也是K/V键值对形式。与tags不同的是,logs还会记录写入logs的时间,因此logs主要用于记录某些事件发生的时间。logs的key值同样必须为字符串,但对value类型则没有限制。例如:

span.LogFields(
log.String(“event”, “soft error”),
log.String(“type”, “cache timeout”),
log.Int(“waited.millis”, 1500),
)

SpanContext

SpanContext携带着一些用于跨服务通信的(跨进程)数据,主要包含:

  • 足够在系统中标识该span的信息,比如:span_id,trace_id
  • Baggage Items,为整条追踪连保存跨服务(跨进程)的K/V格式的用户自定义数据。
Baggage Items

Baggage Items与tags类似,也是K/V键值对。与tags不同的是:

  • 其key跟value都只能是字符串格式
  • Baggage items不仅当前span可见,其会随着SpanContext传递给后续所有的子span。要小心谨慎的使用baggage items——因为在所有的span中传递这些K,V会带来不小的网络和CPU开销。

References

Opentracing定义了两种引用关系:ChildOfFollowFrom

ChildOf: 父span的执行依赖子span的执行结果时,此时子span对父span的引用关系是ChildOf。比如对于一次RPC调用,服务端的span(子span)与客户端调用的span(父span)是ChildOf关系。

FollowFrom:父span的执不依赖子span执行结果时,此时子span对父span的引用关系是FollowFromFollowFrom常用于异步调用的表示,例如消息队列中consumerspan与producerspan之间的关系。

Trace

Trace表示一次完整的追踪链路,trace由一个或多个span组成。下图示例表示了一个由8个span组成的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)

时间轴的展现方式会更容易理解:

––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–––––––|–> time[Span A···················································][Span B··············································][Span D··········································][Span C········································][Span E·······]        [Span F··] [Span G··] [Span H··]

4.基于jaegertracing 实现全链路追踪

认识 Jaeger :

Jaeger 是Uber开发的一套分布式追踪系统,受启发于 dapper 和 OpenZipkin,兼容 OpenTracing 标准,CNCF的开源项目。

Jaeger 系统框架:

  • Jaeger Client - 为不同语言实现了符合 OpenTracing 标准的 SDK。应用程序通过 API 写入数据,client library 把 trace 信息按照应用程序指定的采样策略传递给 jaeger-agent。
  • Agent - 是一个监听在 UDP 端口上接收 span 数据的网络守护进程,它会将数据批量发送给 collector。它被设计成一个基础组件,推荐部署到所有的宿主机上。Agent 将 client library 和 collector 解耦,为 client library 屏蔽了路由和发现 collector 的细节。
  • Collector - 接收 jaeger-agent 发送来的数据,然后将数据写入后端存储。Collector 被设计成无状态的组件,因此您可以同时运行任意数量的 jaeger-collector。
  • Data Store - 后端存储被设计成一个可插拔的组件,支持将数据写入 cassandra、elastic search。
  • Query - 接收查询请求,然后从后端存储系统中检索 trace 并通过 UI 进行展示。Query 是无状态的,您可以启动多个实例,把它们部署在 nginx 这样的负载均衡器后面。

作为链路信息的生产者,只需要使用Jaeger-client 的API 写入数据即可。

Jaeger-client 也支持多种语言,在这里使用Jaeger-client-cpp 来展示一下,如何跨请求追踪:

OpenTracing 是将span的SpanContext 注入了HTTPheader 来实现传递span的。

所以我们需要先继承它提供的读写类:

1.继承opentracing::HTTPHeadersWriter 并重写set 函数,将SpanContext 写入HTTPheader

class CustomHeaderWriter : public opentracing::HTTPHeadersWriter{public:CustomHeaderWriter(httplib::Headers* headers) {headers_ =headers;}~CustomHeaderWriter(){headers_=nullptr;}opentracing::expected<void> Set(opentracing::string_view key, opentracing::string_view value) const{headers_->emplace(key.data(), value.data());opentracing::expected<void> _void;return _void;};private:httplib::Headers* headers_;
};

2.继承opentracing::HTTPHeadersReader 并重写ForeachKey,从HTTPHeader里将SpanContext读出来

class CustomHeaderReader : public  opentracing::HTTPHeadersReader {public:CustomHeaderReader(const httplib::Request* req) {req_ = req;};~CustomHeaderReader(){req_=nullptr;};opentracing::expected<void>   ForeachKey(std::function<opentracing::expected<void> (opentracing::string_view key, opentracing::string_view value)> f) const {for(auto it = req_->headers.begin(); it!=req_->headers.end();it++){auto result = f(it->first, it->second);if (!result) return result;}return {};};private:const httplib::Request* req_;
};

使用样例

注入请求(假设请求目标为下ExtractDemo):

int InjectDemo(){//init tracerauto configYAML = YAML::LoadFile("JaegerConfigPATH");auto config = jaegertracing::Config::parse(configYAML);auto tracer = jaegertracing::Tracer::make("servername", config, jaegertracing::logging::consoleLogger());opentracing::Tracer::InitGlobal( std::static_pointer_cast<opentracing::Tracer>(tracer));auto root_span = opentracing::Tracer::Global()->StartSpan("start a span");httplib::Headers headers;CustomHeaderWriter header_write(&headers);opentracing::Tracer::Global()->Inject(root_span->context(), header_write); //inject ctxstring host;httplib::Client cli(host.c_str()); //request host addressstring path;                       //request pathstring req_data;                    auto res = cli.Post(path.c_str(),headers, req_data, "application/octet-stream"); //transmit root_span.contextif(res->status!=200){//err}root_span->Finish();opentracing::Tracer::Global()->Close();return 0;
}

解析请求,并继承上面的span (假设请求来自上InjectDemo)

int ExtractDemo(){//init tracerauto configYAML = YAML::LoadFile("JaegerConfigPATH");auto config = jaegertracing::Config::parse(configYAML);auto tracer = jaegertracing::Tracer::make("apiservername", config, jaegertracing::logging::consoleLogger());opentracing::Tracer::InitGlobal( std::static_pointer_cast<opentracing::Tracer>(tracer));httplib::Server server;server.Post("/cci_ai/service/v1/layout_analysis", [](const httplib::Request &req, httplib::Response &res) {  CustomHeaderReader carrier(&req);//use a request init a carrierauto context = opentracing::Tracer::Global()->Extract(carrier); // get a context from a carrierauto span = opentracing::Tracer::Global()->StartSpan("doLayoutAnalysis", { opentracing::ChildOf(context->get()) });//use this context make a child_span{//with this span , you can make relation with the request}span->Finish();});server.listen("0.0.0.0",8080);opentracing::Tracer::Global()->Close();return 0;
}

关于配置文件:

config.yaml

disabled: false
reporter:logSpans: true
sampler:type: constparam: 1

如果不配置localAgentHostPort 的话,默认链路信息会被127.0.0.1:6831 收集,

如果想指定jaeger-agent ,在reporter下 添加 localAgentHostPort: jaeger-agent:6831

具体描述可以点击查看源项目描述

5.如何查看追踪信息 ?

使用docker 部署一下jaeger-ui:
docker pull jaegertracing/all-in-one:1.21
docker run -d -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one:latest

访问 http://localhost:16686/search 就可以根据service 查到相关追踪信息了

快速入门Opentracing-cpp相关推荐

  1. 深入浅出Istio:Service mesh快速入门与实践-读书笔记(By GisonWin)

    01 服务网格历史 (以后补充) 02 服务网格的基本特性 连接 微服务错综复杂,要完成其业务目标,连接问题是首要问题.连接存在于所有服务的整个lifcecycle中,用于维持服务的运行. 安全 保障 ...

  2. QT快速入门、三点求圆心实现详解

    在编程中,会经常用到数学计算,所以C++将常用的数学计算,例如求正余弦等,封装成函数(正是我们在3.2 数学计算中学习到的),我们只需要写入简单的语句就可以执行所需要的功能,这正是函数的意义.在这一章 ...

  3. automake linux,Linux下automake软件编译与发布快速入门

    Linux下automake软件编译与发布快速入门 2008-04-22 eNet&Ciweek 进入编辑界面,输入内容如下: AUTOMAKE_OPTIONS=foreign bin_PRO ...

  4. [vs2010 project] CppUnit快速入门

    简介 测试是软件开发过程中极其重要的一环,详尽周密的测试能够减少软件BUG,提高软件品质.测试包括单元测试.系统测试等.其中单元测试是指针对软件功能单元所作的测试,这里的功能单元可以是一个类的属性或者 ...

  5. 【C++快速入门】面向对象篇

    面向对象 类与对象 对象的内存布局 *this 与 指针访问对象成员的本质 封装性 内存空间的布局 堆空间 memset与堆内存的初始化 对象的内存(数据段.栈空间.堆空间) 构造函数(Constru ...

  6. 【C++快速入门】基础语法篇

    C++基础语法 C++介绍 cin.cout 函数重载(Overload) 默认参数 extern "C" #pragma once 内联函数(inline function) 内 ...

  7. Boost Graph Library 快速入门

    Boost Graph Library 快速入门 图领域的数据结构和算法在某些方面比容器更为复杂,图算法在图中移动有着众多的路线,而STL使用的抽象迭代器接口不能有效的支持这些.作为替换,我们为图提供 ...

  8. CppUnit快速入门

    From:http://blog.csdn.net/freefalcon/archive/2006/05/25/753819.aspx 简介 测试是软件开发过程中极其重要的一环,详尽周密的测试能够减少 ...

  9. 【个人笔记】OpenCV4 C++ 快速入门 02课

    个人资料,仅供学习使用 修改时间--2022年2月6日 11:40:46 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 02 图像色彩空间转换 opencv知识点: 色彩空间 ...

  10. 【个人笔记】OpenCV4 C++ 快速入门 00课

    个人资料,仅供学习使用 修改时间--2022年2月5日 11:52:56 学习课程:OpenCV4 C++ 快速入门视频30讲 视频老师:贾志刚 00 环境配置与搭建 + 显示1张图片 本课解决的问题 ...

最新文章

  1. VTK:InfoVis之XGMLReader
  2. 处理数字_2_计算某列的平均值
  3. html5退出全屏触发的方法_好程序员web前端分享HTML5常见面试题集锦二
  4. SAS实现四十年连续增长,2015年全球营收达31.6亿美元
  5. 为什么 IEnumerable 没有提供 ForEach ?
  6. 生活感悟——和尾号990的滴滴师傅的聊天
  7. 红橙Darren视频笔记 view的invalidate调用draw方法的流程(源码分析基于api 29)
  8. Java发送HTTP POST请求(内容为xml格式)
  9. python分布式开发容易吗_Python能实现分布式的进程吗?
  10. 移动滑块改变使用容量
  11. 服务器进销财务管理系统,进销存财务管理系统
  12. 敏感词过滤和谐社会1.0版
  13. 惠普计算机图标不在桌面,惠普笔记本电脑桌面图标显示图标不正常如何还原 惠普笔记本电脑桌面图标显示图标不正常还原的方法...
  14. 照片墙背景html图片,微信照片墙背景图片
  15. Oracle EBS使用CSV导入Oracle Form及BOM清单导入 API
  16. 代数结构入门:群、环、域、向量空间
  17. 人工智能实战2019第八次作业 16721088 焦宇恒
  18. 华为云+AI+5G,点燃2020政企智能升级
  19. “坝上”到底在哪里?
  20. Android第三方QQ登录、获取个人信息、分享实现

热门文章

  1. error: ‘CV_LOAD_IMAGE_UNCHANGED’ was not declared in this scope
  2. 事件clientX、pageX、screenX、offsetX
  3. mysql neq_neq、eq的用法,thinkphp框架下的
  4. 王者荣耀KPL秋季赛总决赛预测(AG VS DYG)
  5. 阿里资深技术专家:如何对复杂的业务系统进行解耦和重构?
  6. 【数据仓库】数仓好坏衡量标准
  7. 【程序】Marvell 88W8686 WiFi模块(WM-G-MR-09)创建或连接热点,并使用lwip2.0.3建立http服务器(20180312版)
  8. 完美解决Mac无法写入NTFS硬盘——Mounty for NTFS
  9. 求两点连线与其中一点为球心球的交点——赋MATLAB代码
  10. 2021年超全超详细的最新大数据开发面试题,附答案解析