《zipkin》一 了解zipkin

1.ZipKin介绍

Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System),基于 Google Dapper(https://bigbully.github.io/Dapper-translation/)的论文设计而来,由 Twitter 公司开发贡献。其主要功能是聚集来自各个异构系统的实时监控数据。分布式跟踪系统还有其他比较成熟的实现,例如:Naver的Pinpoint、Apache的HTrace、阿里的鹰眼Tracing、京东的Hydra、新浪的Watchman,美团点评的CAT,skywalking等。

2. ZipKin的意义

大型互联网公司为什么需要分布式跟踪系统?为了支撑日益增长的庞大业务量,我们会把服务进行整合、拆分,使我们的服务不仅能通过集群部署抵挡流量的冲击,又能根据业务在其上进行灵活的扩展。一次请求少则经过三四次服务调用完成,多则跨越几十个甚至是上百个服务节点。如何动态展示服务的链路?如何分析服务链路的瓶颈并对其进行调优?如何快速进行服务链路的故障发现?这就是服务跟踪系统存在的目的和意义。

3. 服务跟踪系统的要求

即使作为分布式系统的开发者,也很难清楚的说出某个服务的调用链路,况且服务调用链路还是动态变化的,这时候只能咬咬牙翻代码了。接下来,我们看看Zipkin是如何做到这一点的。在这之前,我们先来简单讨论一下分布式跟踪系统的设计要点,
第一点:对应用透明、低侵入。为什么说这一点最重要?因为分布式系统面对的客户是开发者,如果他们的系统需要花费较大的改造才能接入你的分布式跟踪系统,除非你是他的老板,否则他会直接和你说:No!!没人用是最惨的结果。那么怎么才能做到对业务系统最低的侵入性呢?Dapper给出的建议是在公共库和中间件上做文章。没错,分布式系统之间的通讯靠的都是RPC、MQ等中间件系统,即使是内部使用的线程池或者数据库连接池,大多也是使用经过公司包装公共库,这就给服务跟踪带来了机会,我只要对中间件和公共库进行改造,就几乎可以做到全方位跟踪,当然,这也是有难度的;
第二点:低开销、高稳定。大多数应用不愿意接入监控系统的原因是怕影响线上服务器的性能,特别是那些对性能特别敏感的应用,所以,分布式跟踪系统一定要轻量级,不能有太复杂的逻辑和外部依赖,甚至需要做到根据服务的流量来动态调整采集密度。
第三点:可扩展。随着接入的分布式系统的增多,压力也将不断增长,分布式跟踪系统是否能动态的扩展来支撑不断接入的业务系统,这也是设计时需要考虑的。可以看出,这三点并没有什么特别,对于服务降级系统、分布式跟踪系统和业务监控系统等,这三点都是必须的。

4.ZipKin架构

ZipKin可以分为两部分,一部分是zipkin server,用来作为数据的采集存储、数据分析与展示;zipkin client是zipkin基于不同的语言及框架封装的一些列客户端工具,这些工具完成了追踪数据的生成与上报功能,架构如下:
《zipkin》一 了解zipkin_第1张图片
Zipkin Server主要包括四个模块:
(1)Collector 接收或收集各应用传输的数据
(2)Storage 存储接受或收集过来的数据,当前支持Memory,MySQL,Cassandra,ElasticSearch等,默认存储在内存中。
(3)API(Query) 负责查询Storage中存储的数据,提供简单的JSON API获取数据,主要提供给web UI使用
(4)Web 提供简单的web界面
Instrumented client和server是分别使用了ZipKin Client的服务,Zipkin Client会根据配置将追踪数据发送到Zipkin Server中进行数据存储、分析和展示。

服务追踪流程如下:
《zipkin》一 了解zipkin_第2张图片

下面通过图二解释一次http client请求的工作原理,红线表示没有接入zipkin时一次http请求的调用过程,用户发起一次GET请求,由http client执行后返回响应结果,中间无其他过程。在接入zipkin后,一次http请求则携带了其他信息:在http client执行请求前,先由trace instrumentation记录这次请求的trace信息以及时间戳,然后才由http client去真正执行GET请求,在执行完返回响应结果时,再由trace instrumentation记录下当前时间戳,并计算出这次请求的持续时间,最后将响应结果返回给用户,即与trace instrumentation追踪器的交互集中发生在两个时刻,分别是在客户端发送和客户端接收的时候,在整个请求执行完后,追踪器将这次请求的span信息异步发送到zipkin的收集器。此时完成了一次请求的追踪。

5. ZipKin几个概念

在追踪日志中,有几个基本概念spanId、traceId、parentId
traceId:用来确定一个追踪链的16字符长度的字符串,在某个追踪链中保持不变。
spanId:区域Id,在一个追踪链中spanId可能存在多个,每个spanId用于表明在某个服务中的身份,也是16字符长度的字符串。
parentId:在跨服务调用者的spanId会传递给被调用者,被调用者会将调用者的spanId作为自己的parentId,然后自己再生成spanId。
刚发起调用时traceId和spanId是一致,parentId不存在。
被调用者的traceId和调用者的traceId时一致的,被调用者会产生自己的spanId,并且被调用者的parentId是调用者的spanId

5. span模型

Zipkin中的Span主要包含三个数据部分:
1.基础数据
用于跟踪树中节点的关联和界面展示,包括traceId、spanId、parentId、name、timestamp和duration,其中parentId为null的Span将成为跟踪树的根节点来展示,当然它也是调用链的起点,为了节省一次spanId的创建开销,让顶级Span变得更明显,顶级Span中spanId将会和traceId相同。timestamp用于记录调用的起始时间,而duration表示此次调用的总耗时,所以timestamp+duration将表示成调用的结束时间,而duration在跟踪树中将表示成该Span的时间条的长度。需要注意的是,这里的name用于在跟踪树节点的时间条上展示。
2.Annotation数据
用来记录关键事件,只有四种,cs(Client Send)、sr(Server Receive)、ss(Server Send)、cr(Client Receive),所以在Span模型中,Annotation是一个列表,长度最多为4。每种关键事件包含value、timestamp和endpoint,value就是cs、sr、ss和cr中的一种,timestamp表示发生的时间,endpoint用于记录发生的机器(ip)和服务名称(serviceName)。可以很自然的想到,cs和cr、sr和ss的机器名称是相同的,为了简单起见,cs和cr的服务名称可以一样,sr和ss的服务名称可以一样。Annotation数据主要用于用户点击一个Span节点时展示具体的Span信息。
3.BinaryAnnotation数据
我们并不满足在跟踪树上只展示调用链的时间信息,如果需要绑定一些业务数据(日志)的话,可以将数据写入BinaryAnnotation中,它的结构和Annotation数据一模一样,在Span中也是一个列表,这里就不再阐述,但BinaryAnnotation中不宜放太多数据,不然将导致性能和体验的下降。

现在我们已经了解了一个Span的内部结构,但这是Span的最终形态,也就是说这是Zipkin在收集完数据并展现给用户锁看到的最终形态。Span的产生是“不完整”的,
Zipkin服务端需要将搜集的有同一个traceId和spanId的Span组装成最终完整的Span,也就是上面说到的Span,如下图所示:
《zipkin》一 了解zipkin_第3张图片
这里我们看到,Gateway、Service1、Service2和Service3都在往Zipkin发送跟踪数据,你一定会感觉奇怪,Gateway作为服务调用的起点,难道不是由Service1、Service2和Service3把各自的跟踪数据传回Gateway然后再由Gateway统计并整理好一并发往Zipkin服务端吗?认真想想就知道这种设计的弊端,如果一次完整的服务请求调用链路特长,比如设计上百个服务节点的通讯,那么将各服务节点的span信息传回给顶级span和将跟踪数据汇总并发送到Zipkin将带来巨大的网络开销,这是不值当的,还不如将跟踪数据组装的任务直接交给Zipkin来做,这样Zipkin的客户端SDK不需要有过于复杂的逻辑,也节省了大量的网络带宽资源,可扩展性大大提高。

你可能感兴趣的:(java开发中间件)