基于Zipkin的Thrift服务RPC调用链跟踪

JavaScript0110

基于Zipkin的Thrift服务RPC调用链跟踪,第1张

我们现在所处的生产环境是一个集Nodejs, Go, Java, Ruby, Scala等多种语言程序的混合场景.Twitter的Finagle框架, 是一个基于Thrift协议的RPC框架,其中Zipkin是针对Finagle框架的一个基于Thrift协议的RPC调用链跟踪的工具,可搜集各服务调用数据,并提供分析查询展示功能。帮助识别分布式RPC调用链里,哪一个调用比较耗时,性能有问题,以及是否有异常等,使得诊断分布式系统性能成为可能。

一次服务调用追踪链路,由一组Span组成。需在web总入口处生成TraceID,并确保在当前请求上下文里能访问到

表示某个时间点发生的Event

存放用户自定义信息,比如:sessionID、userID、userIP、异常等

表示一次完整RPC调用,是由一组Annotation和BinaryAnnotation组成。是追踪服务调用的基本结构,多span形成树形结构组合成一次Trace追踪记录。Span是有父子关系的,比如:Client A、Client A ->B、B ->C、C ->D、分别会产生4个Span。Client A接收到请求会时生成一个Span A、Client A ->B发请求时会再生成一个Span A-B,并且Span A是 Span A-B的父节点

Trace的基本信息需在上下游服务之间传递,如下信息是必须的:

一个完整Trace 由一组Span组成,这一组Span必须具有相同的TraceID;Span具有父子关系,处于子节点的Span必须有parent_id,Span由一组 Annotation和BinaryAnnotation组成。整个Trace Tree通过Trace Id、Span ID、parent Span ID串起来的。

经过上述三条,用户任何访问所引起的后台服务间调用,完全可以串起来,并形成一颗调用树。通过调用树,哪个调用耗时多久,是否有异常等都可清晰定位到。

testService(Web服务) ->OrderServ(Thrift) ->StockServ &PayServ(Thrift)。一共有四个服务,testService 调用 OrderServ、OrderServ同时调用 StockServ和PayServ。需生成的Trace信息如下:

我们针对跟踪数据的收集的统一接入点, 为kafka.所有应用产生的zipkin数据统一发送到Kafka集群中.具体的channel为: EAGLEYE_ZIPKIN_CHANNEL.

JSON串范例(格式化):

备注: span信息的json,添加'span'头信息, 在通过kafka做收集时, 通过该头信息将span信息路由到独立的es的index中. 每一条span记录其实是半个span信息, 要么是client端产生的, 要么是server端产生的.

收集了Zipkin产生的RPC调用链信息,并给服务治理框架提供跟踪信息检索(双击某行有问题的Span记录可以查看某次调用链详情,了解具体的网络情况和业务执行情况)

Zipkin的拓扑服务zipkin-dependencies是作为zipkin的一个独立的离线服务,也就是说,只启动zipkin服务,是没法看到拓扑的,还需要自己离线启动zipkin-dependencues服务。

其中ES配置参数如下:

Zipkin出了支持elasticsearch存储,还有mysql,cassard,详细配置信息请看 源码Readme

1、图中线条说明

服务之间的线条,遵循以下原则:

2、主调被调次数说明

点开每一个服务,可以看到主调被调,比如我在拓扑图中点击

某个服务,可以与此服务有直接调用关系的服务有哪些,效果如下:

其中Uses by表示此服务作为被调服务,被哪些服务调用了;Uses表示此服务调用了哪些其他服务。

在上面的图中点击某个主调或被调服务,即可看到具体的调用次数,以及失败次数,效果如下:

通过拓扑图,宏观上,我们可以快速了解服务之间的调用关系,同时也可以知道哪些服务间调用有问题,且可以知道出现问题的一个量级是多少(失败数,调用总数)。

Zipkin拓扑denpendencies是基于上报的链路span数据再次构建出的描述链路拓扑的一种新的数据结构。

构建链路的第一步就是读取Span数据。Zipkin外部数据源支持三种,分别是Mysql,Cassandra,Elasticsearch,因此构建拓扑时,将从这三种数据源中读取Span数据。

读取Span数据源后,需要对其处理,计算出链路的拓扑。因为Span的数据量很大,普通程序计算处理无法完成任务,因此需要用到大数据框架。Zipkin官方选用的是Spark框架。Spark对Span数据进行处理,最后生成拓扑数据DenpendencyLink,然后持久化到存储中。

前端请求拓扑(DependencyLink)时,即按照查询条件,查询已经持久化后的DependencyLink,然后经过UI渲染,进行页面展示。

启动Zipkin-dependencies服务时,会传入几个参数,分别是时间day和存储类型storageType。Zipkin-dependencies服务是以天为单位进行建立拓扑,因此day将决定建立那一天的拓扑;而storageType将决定从什么储存中读取数据。

1、获取日期:

2、获取存储类型:

3、根据不同的存储启动不同的jOb:

不同的存储会定义不同Job类,因此有CassandraDependenciesJob,MySQLDependenciesJob,MySQLDependenciesJob,ElasticsearchDependenciesJob。 不同的Job主要区别在于读取Span的方式不同,而Spark对Span进行处理计算的方式基本都是相同的。 本文主要分析ElasticsearchJOb。

Job中主要逻辑都在run方法中,ElastichserchJob的Run方法定义如下:

主要步骤如下:

1、首先通过Spark的配置属性Conf,创建一个JavaSparkContext对象sc:

2、然后读取elasticsearch span数据源:

3、读取数据源后,就可以对Span进行处理了,首先按照TraceId 进行Group分组:

其中JSON_TRACE_ID Function定义如下:

4、Span按照TraceId Group 分组后,接着对Span进行处理, 创建出DenpendencyLink。

5、上面方法最终返回的是个Map类型,将其转化为pari类型,再对其进行一个reduceByKey操作:

6、Spark对Span的计算操作到这儿基本就完成了,最后将DependencyLink转化为Jso形式:

7、对于计算好的拓扑Links,将其持久化到Elasticsearch中:

整个过程到此完毕,其中最复杂也是最核心的逻辑就是计算出链路拓扑Denpendencylink,此步骤在Function TraceIdAndJsonToDependencyLinks(logInitializer, decoder)中。接下来详细分析TraceIdAndJsonToDependencyLinks完成的工作。

首先介绍一下DenpendencyLink数据结构。DenpendencyLink就是最终与页面交互的拓扑结构数据单元,字端有:

DenpendencyLink类定义如下:

TraceIdAndJsonToDependencyLinks类的定义如下:

其中call方法中,首先完成对同一TraceId的Span解码:

然后,通过DependencyLinker类构造出DependendyLink,首先构造一个SpanNode Tree:

然后利用深度优先遍历方法遍历整个,统计出CallCounts和errorCounts:

其中callCounts和errorCounts定义如下:

最后,再通过callCounts和errorCounts生成List<DependencyLink>:

这样,最终构建出了DependencyLink。

本文为我的调用链系列文章之一,已有文章如下:

祝大家工作顺利,天天开心!

Zipkin是一个分布式链路跟踪系统,可以采集时序数据来协助定位延迟等相关问题。数据可以存储在cassandra,MySQL,ES,mem中。分布式链路跟踪是个老话题,国内也有类似的框架,比如阿里的skywalking。 zipkin目前和SpringCloud生态结合紧密,有相关的支持。

主要包括客户端和一个管理服务端。在客户端采集数据后,发送给服务端,用来展示数据。在每个instrumented的客户端,写入了traceId,然后统一收集数据在服务端存储。这里instrumented翻译过来是仪器化,设备化,为了简单我把他称作 标识实体 ,代表一个接入了zipkin的客户端。

zipkin包括四个组件,collector,storage,search,webUI。其中collector中重点有两个

zipkin可以跟踪多种请求,如async方法,schedule,rxjava等,都在 org.springframework.cloud.sleuth.instrument 包下,这里以web请求做介绍。在SpringCloud下用sleuth来做跟踪处理。具体通过一个拦截器 org.springframework.cloud.sleuth.instrument.web.TraceHandlerInterceptor 实现,如下

zipkin支持mem,MySQL,ES存储方式,以 io.zipkin.java:zipkin-server:2.6.1 为例,可以通过配置实现。具体配置项可以在 zipkin-server-shared.yaml 中查看,如下:

同时,举例用MySQL作为存储时的一张span对象表,如下:

一般来说,分布式的链路跟踪数据是比较大量的,建议采用ES来存储,方便支持分区,以及后期的扩展等,比如使用某些字段来存储非结构化数据。

以上就是所有内容,下面是一个请求和记录展示。