背景
腾讯发布了TSW服务,官网简介如下
腾讯微服务观测平台 TSW(Tencent Service Watcher,TSW)为您提供云原生服务可观察性解决方案。腾讯微服务观测平台 TSW 能够追踪到分布式架构中的上下游依赖关系,绘制拓扑图,为您提供服务、接口、实例、中间件等多维度调用观测,助您掌控系统关键指标,及时发现错误调用与性能瓶颈。腾讯微服务观测平台 TSW 支持各类主流框架与协议,兼容业界通用的 Opentracing 标准,拥抱开源生态,支持多种主流编程语言。腾讯微服务观测平台 TSW 助您提高服务可观测性,做微服务系统的医生,实时观测您微服务系统的健康。
之前在做Fission相关工作的时候,了解过Istio相关的功能,当时就挺好奇,分布式链路追踪是如何实现的,动起来,就不会难。
OpenTracing 简介
早期的软件架构多为C/S模式,在debug、trace上面都做出了很多贡献,例如java中的printStackTrace
就是标准的追踪逻辑,清楚的展示了函数之间的调用关系。但随着面向服务架构的普及(Service Oriented Architecture,简称SOA),原本单机的任务被越来越多的解藕成多个任务,微服务的概念随之普及,但对于trace的需求依旧存在,如此就诞生了分布式链路追踪的技术。
开放分布式追踪规范(OpenTracing),提供了在记录追踪一个请求在分布式系统中的调用过程的任务中的一些规范。
例如下图,一个请求需要调用多个后台服务,在单机系统中,这些调用顺序会体现在一个一个函数的调用上,但在分布式系统中,这些调用都是跨进程、跨主机的调用。
追踪的效果会体现在下图中,达到和单机服务上追踪函数类似的效果。
为了达成信息采集的目的,往往需要侵入用户代码,这就需要一个统一的API规范,减少在不同系统中迁移时的痛苦。
OpenTracing语义标准,详见github文档,下面整理一些核心的内容
OpenTracing数据模型
Trace, 调用链
Span,可以理解成一个一个的微服务,例如上图中的auth就是一个span。
Span可以被翻译为跨度,可以被理解为一次方法调用, 一个程序块的调用, 或者一次RPC/数据库访问.只要是一个具有完整时间周期的程序访问,都可以被认为是一个span.
Span包含以下的状态
operation name:操作名称
start timestamp:起始时间
finish timestamp:结束时间
Span Tag:键值对构成的标签集合
Span Log:每次log操作,包含一个键值对和一个时间戳
SpanContext:Span的上下文对象
- OpenTracing的实现需要将当前的调用链状态(例如trace和trace id)依赖于一个独特的Span去跨进程边界传输。
- Baggage Items,。。。
References:Span与Span之间的关系
Opentracing定义了两种关系(目前定义的关系都是因果关系):
- ChildOf:父子关系,一个父级Span会有很多孩子Span,他们通常是可以并行执行的,父Span会合并所有子span的结果,并在规定的时间期限内返回
- FollowFrom:跟随关系,一些父级节点,不依赖任何他们子节点的执行结果,这时我们称子span和父span之间是FollowFrom的因果关系
一条Trace,可以被认为是由多个span组成的有向无环图,例如下图中的例子
1 | Causal relationships between Spans in a single Trace |
或者使用下面的时间轴的时序图来更好的展现Trace
1 | Temporal relationships between Spans in a single Trace |
OpenTracing API
Tracer
Tracer接口用来创建Span,以及处理如何处理Inject(可以理解是存储SpanContext到载体中)和Extract(从载体中提取Context信息),用于跨进程边界传输。
- 创建一个新Span,需要提供
- Span操作名称(必填)
- 零个或者多个关联的SpanContext,如果可能指定关系类型(选填)
- 开始时间(选填)
- 零个或者多个tag(选填)
- 将SpanContext注入(Inject)到carrier,需要提供
- SpanContext实例
- format格式化描述,一般会是一个字符串常量
- carrier,根据format确定。Tracer实现根据format指定的格式,将SpanContext序列化到carrier对象中
- 将SpanContext从carrier中进行提取(Extract),需要提供如下信息,编码格式和数据存储载体carrier
- format
- carrier
上文中提到的格式通常有基于字符串、HTTP Header、Binary三种
Span
好多,看起来还是无感,暂且不整理了
相关框架
Zipkin
zipkin是开放分布式追踪系统的一个实现。从该框架开始,探索相关问题。好像并没有从该框架开始
SkyWalking
优点
尝试使用了SkyWalking的Go版本客户端go2Sky,发现其有如下优点:
- SkyWalking发送Span监控信息,采用的是异步发送逻辑,在单机上可以达到很好的性能。
- 代码在业务逻辑中的嵌入较少,和输出Log的代码逻辑相当(但仍是嵌入式的)。
- 引入上线部署的速度很快,不需要额外的基础组件的支持(对比有agent的服务,在下面的Jaeger中会有相关介绍)
缺点
但其在grpc投递中(其他投递方式未了解)并不能保证所有Span的可靠投递,主要表现在如下几个方面:
- 在因为网络问题发送失败的时候,客户端会等待一段时间再继续发送,此段时间缓冲区会被持续消耗,在缓冲区耗尽之后,新生成的ReportSpan将会被抛弃(即使不因为网络故障,也会存在溢出丢失的问题)。相关代码
- 如果某条Span发送失败了,并没有重试的机制,也没有失败回调函数的接口,无法有效通知给用户。相关代码
此外在性能方面也会有如下问题(主要是和有agent组件的服务相比):
- SkyWalking都是每个独立reporter向服务器端发送Span,在大规模微服务中缺少有效的聚合压缩,容易造成服务器端压力大。
- 需要在每个reporter上固定配置服务器端地址,不利于在服务器端发生变动时快速调整所有的客户端上报地址。
Jaeger
快速体验
服务端:快速安装体验官网文档,快速启动 Jaeger UI, collector, query, and agent服务
客户端:官网文档
架构设计
官网文档,下列内容来自官网的摘抄,帮助自己快速回忆重点。
Span
Jaeber Client Library
整体架构图
- 采用了agent的设计,如此只需要在每台物理机上,创建好一个agent,就可以采集该物理机上的所有的Span数据,然后统一发送给Controller
- controller负责接收、验证、转换、存储trace
可靠性调查
- 默认情况下jaeger客户端通过UDP协议向jaeger-agent发送已经Finished 的Span。在Java版本中还会提供HttpSender的版本,但其他语言暂不支持。
- jaeger客户端会上报指标类型的数据来汇报自身的工作情况,例如:
- 已经开始、结束的Spand的数量
- 采样丢掉和保留的数量
- 在解码处理过程中的出错的数量等
上述两点参考官网文档-客户端