服务链路追踪(Spring Cloud Sleuth)

sleuth:英 [slu:θ] 美 [sluθ] n.足迹,警犬,侦探vi.作侦探html

  微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统每每有不少个服务单元。因为服务单元数量众多,业务的复杂性,若是出现了错误和异常,很难去定位。主要体如今,一个请求可能须要调用不少个服务,而内部服务的调用复杂性,决定了问题难以定位。因此微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每一个请求的步骤清晰可见,出了问题,很快定位。前端

举几个例子:java

一、在微服务系统中,一个来自用户的请求,请求先达到前端A(如前端界面),而后经过远程调用,达到系统的中间件B、C(如负载均衡、网关等),最后达到后端服务D、E,后端通过一系列的业务逻辑计算最后将数据返回给用户。对于这样一个请求,经历了这么多个服务,怎么样将它的请求过程的数据记录下来呢?这就须要用到服务链路追踪。mysql

二、分析微服务系统在大压力下的可用性和性能。git

Zipkin能够结合压力测试工具一块儿使用,分析系统在大压力下的可用性和性能。github

设想这么一种状况,若是你的微服务数量逐渐增大,服务间的依赖关系愈来愈复杂,怎么分析它们之间的调用关系及相互的影响?web

spring boot对zipkin的自动配置可使得全部RequestMapping匹配到的endpoints获得监控,以及强化了RestTemplate,对其加了一层拦截器,使得由它发起的http请求也一样被监控。redis

 

Google开源的 Dapper链路追踪组件,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇文章是业内实现链路追踪的标杆和理论基础,具备很是大的参考价值。spring

目前,链路追踪组件有Google的Dapper,Twitter 的Zipkin,以及阿里的Eagleeye (鹰眼)等,它们都是很是优秀的链路追踪开源组件。sql

本文主要讲述如何在Spring Cloud Sleuth中集成Zipkin。在Spring Cloud Sleuth中集成Zipkin很是的简单,只须要引入相应的依赖和作相关的配置便可。

1、简介

Spring Cloud Sleuth 主要功能就是在分布式系统中提供追踪解决方案,而且兼容支持了 zipkin,你只须要在pom文件中引入相应的依赖便可。

2、服务追踪分析

微服务架构上经过业务来划分服务的,经过REST调用,对外暴露的一个接口,可能须要不少个服务协同才能完成这个接口功能,若是链路上任何一个服务出现问题或者网络超时,都会造成致使接口调用失败。随着业务的不断扩张,服务之间互相调用会愈来愈复杂。

Paste_Image.png

随着服务的愈来愈多,对调用链的分析会愈来愈复杂。它们之间的调用关系也许以下:

Paste_Image.png

3、术语

Spring Cloud Sleuth采用的是Google的开源项目Dapper的专业术语。

  • Span:基本工做单元,例如,在一个新建的span中发送一个RPC等同于发送一个回应请求给RPC,span经过一个64位ID惟一标识,trace以另外一个64位ID表示,span还有其余数据信息,好比摘要、时间戳事件、关键值注释(tags)、span的ID、以及进度ID(一般是IP地址) 
    span在不断的启动和中止,同时记录了时间信息,当你建立了一个span,你必须在将来的某个时刻中止它。
  • Trace:一系列spans组成的一个树状结构,例如,若是你正在跑一个分布式大数据工程,你可能须要建立一个trace。
  • Annotation:用来及时记录一个事件的存在,一些核心annotations用来定义一个请求的开始和结束 
    • cs - Client Sent -客户端发起一个请求,这个annotion描述了这个span的开始
    • sr - Server Received -服务端得到请求并准备开始处理它,若是将其sr减去cs时间戳即可获得网络延迟
    • ss - Server Sent -注解代表请求处理的完成(当请求返回客户端),若是ss减去sr时间戳即可获得服务端须要的处理请求时间
    • cr - Client Received -代表span的结束,客户端成功接收到服务端的回复,若是cr减去cs时间戳即可获得客户端从服务端获取回复的全部所需时间 

将Span和Trace在一个系统中使用Zipkin注解的过程图形化:

Paste_Image.png

4、sleuth与Zipkin关系?

spring cloud提供了spring-cloud-sleuth-zipkin来方便集成zipkin实现(指的是Zipkin Client,而不是Zipkin服务器),该jar包能够经过spring-cloud-starter-zipkin依赖来引入。

5、Zipkin

Zipkin是什么
Zipkin分布式跟踪系统;它能够帮助收集时间数据,解决在microservice架构下的延迟问题;它管理这些数据的收集和查找;Zipkin的设计是基于谷歌的Google Dapper论文。
每一个应用程序向Zipkin报告定时数据,Zipkin UI呈现了一个依赖图表来展现多少跟踪请求通过了每一个应用程序;若是想解决延迟问题,能够过滤或者排序全部的跟踪请求,而且能够查看每一个跟踪请求占总跟踪时间的百分比。

为何使用Zipkin
随着业务愈来愈复杂,系统也随之进行各类拆分,特别是随着微服务架构和容器技术的兴起,看似简单的一个应用,后台可能有几十个甚至几百个服务在支撑;一个前端的请求可能须要屡次的服务调用最后才能完成;当请求变慢或者不可用时,咱们没法得知是哪一个后台服务引发的,这时就须要解决如何快速定位服务故障点,Zipkin分布式跟踪系统就能很好的解决这样的问题。

Zipkin原理

针对服务化应用全链路追踪的问题,Google发表了Dapper论文,介绍了他们如何进行服务追踪分析。基本思路是在服务调用的请求和响应中加入ID,标明上下游请求的关系。利用这些信息,能够可视化地分析服务调用链路和服务间的依赖关系

对应Dpper的开源实现是Zipkin,支持多种语言包括JavaScript,Python,Java, Scala, Ruby, C#, Go等。其中Java由多种不一样的库来支持

Spring Cloud Sleuth是对Zipkin的一个封装,对于Span、Trace等信息的生成、接入HTTP Request,以及向Zipkin Server发送采集信息等所有自动完成。Spring Cloud Sleuth的概念图见上图。

Zipkin架构

跟踪器(Tracer)位于你的应用程序中,并记录发生的操做的时间和元数据,提供了相应的类库,对用户的使用来讲是透明的,收集的跟踪数据称为Span;将数据发送到Zipkin的仪器化应用程序中的组件称为Reporter,Reporter经过几种传输方式之一将追踪数据发送到Zipkin收集器(collector),而后将跟踪数据进行存储(storage),由API查询存储以向UI提供数据。
架构图以下:

1.Trace
Zipkin使用Trace结构表示对一次请求的跟踪,一次请求可能由后台的若干服务负责处理,每一个服务的处理是一个Span,Span之间有依赖关系,Trace就是树结构的Span集合;

2.Span
每一个服务的处理跟踪是一个Span,能够理解为一个基本的工做单元,包含了一些描述信息:id,parentId,name,timestamp,duration,annotations等,例如:

{
      "traceId": "bd7a977555f6b982",
      "name": "get-traces",
      "id": "ebf33e1a81dc6f71",
      "parentId": "bd7a977555f6b982",
      "timestamp": 1458702548478000,
      "duration": 354374,
      "annotations": [
        {
          "endpoint": {
            "serviceName": "zipkin-query",
            "ipv4": "192.168.1.2",
            "port": 9411
          },
          "timestamp": 1458702548786000,
          "value": "cs"
        }
      ],
      "binaryAnnotations": [
        {
          "key": "lc",
          "value": "JDBCSpanStore",
          "endpoint": {
            "serviceName": "zipkin-query",
            "ipv4": "192.168.1.2",
            "port": 9411
          }
        }
      ]
}

traceId:标记一次请求的跟踪,相关的Spans都有相同的traceId;
id:span id;
name:span的名称,通常是接口方法的名称;
parentId:可选的id,当前Span的父Span id,经过parentId来保证Span之间的依赖关系,若是没有parentId,表示当前Span为根Span;
timestamp:Span建立时的时间戳,使用的单位是微秒(而不是毫秒),全部时间戳都有错误,包括主机之间的时钟误差以及时间服务从新设置时钟的可能性,出于这个缘由,Span应尽量记录其duration;
duration:持续时间使用的单位是微秒(而不是毫秒);
annotations:注释用于及时记录事件;有一组核心注释用于定义RPC请求的开始和结束;

cs:Client Send,客户端发起请求;
sr:Server Receive,服务器接受请求,开始处理;
ss:Server Send,服务器完成处理,给客户端应答;
cr:Client Receive,客户端接受应答从服务器;

binaryAnnotations:二进制注释,旨在提供有关RPC的额外信息。

3.Transport
收集的Spans必须从被追踪的服务运输到Zipkin collector,有三个主要的传输方式:HTTP, Kafka和Scribe

4.Components
有4个组件组成Zipkin:collector,storage,search,web UI
collector:一旦跟踪数据到达Zipkin collector守护进程,它将被验证,存储和索引,以供Zipkin收集器查找;
storage:Zipkin最初数据存储在Cassandra上,由于Cassandra是可扩展的,具备灵活的模式,并在Twitter中大量使用;可是这个组件可插入,除了Cassandra以外,还支持ElasticSearch和MySQL;  存储,zipkin默认的存储方式为in-memory,即不会进行持久化操做。若是想进行收集数据的持久化,能够存储数据在Cassandra,由于Cassandra是可扩展的,有一个灵活的模式,而且在Twitter中被大量使用,咱们使这个组件可插入。除了Cassandra,咱们原生支持ElasticSearch和MySQL。其余后端可能做为第三方扩展提供。
search:一旦数据被存储和索引,咱们须要一种方法来提取它。查询守护进程提供了一个简单的JSON API来查找和检索跟踪,主要给Web UI使用;
web UI:建立了一个GUI,为查看痕迹提供了一个很好的界面;Web UI提供了一种基于服务,时间和注释查看跟踪的方法。

 

Zipkin下载和启动

有三种安装方法:

Zipkin的使用比较简单,官网有说明几种方式: 
一、容器 
Docker Zipkin项目可以创建docker镜像,提供脚本和docker-compose.yml来启动预构建的图像。最快的开始是直接运行最新镜像:

docker run -d -p 9411:9411 openzipkin/zipkin

二、下载jar 
若是你有java 8或更高版本,上手最快的方法是把新版本做为一个独立的可执行jar,Zipkin使用springboot来构建的:

curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

三、下载源代码运行 
Zipkin能够从源运行,若是你正在开发新的功能。要实现这一点,须要获取Zipkin的源代码并构建它。

# get the latest source
git clone https://github.com/openzipkin/zipkin
cd zipkin
# Build the server and also make its dependencies
./mvnw -DskipTests --also-make -pl zipkin-server clean install
# Run the server
java -jar ./zipkin-server/target/zipkin-server-*exec.jar

一、使用官网本身打包好的Jar运行,Docker方式或下载源代码本身打包Jar运行(由于zipkin使用了springboot,内置了服务器,因此能够直接使用jar运行)。zipkin推荐使用docker方式运行,我后面会专门写一遍关于docker的运行方式,而源码运行方式好处是有机会体验到最新的功能特性,可是可能也会带来一些比较诡异的坑,因此不作讲解,下面我直接是使用官网打包的jar运行过程:
官方提供了三种方式来启动,这里使用第二种方式来启动;

wget -O zipkin.jar 'https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec'
java -jar zipkin.jar

首先下载zipkin.jar,我下载的是zipkin-server-2.10.2-exec.jar,而后直接使用-jar命令运行,要求jdk8以上版本;

D:\workspace\zipkin>java -jar zipkin-server-2.10.2-exec.jar
                                    ********
                                  **        **
                                 *            *
                                **            **
                                **            **
                                 **          **
                                  **        **
                                    ********
                                      ****
                                      ****
        ****                          ****
     ******                           ****                                 ***
  ****************************************************************************
    *******                           ****                                 ***
        ****                          ****
                                       **
                                       **


             *****      **     *****     ** **       **     **   **
               **       **     **  *     ***         **     **** **
              **        **     *****     ****        **     **  ***
             ******     **     **        **  **      **     **   **

:: Powered by Spring Boot ::         (v2.0.3.RELEASE)
...
2018-07-20 14:59:08.635  INFO 17284 --- [           main] o.xnio                                   : XNIO version 3.3.8.Final
2018-07-20 14:59:08.650  INFO 17284 --- [           main] o.x.nio                                  : XNIO NIO Implementation Version 3.3.8.Final
2018-07-20 14:59:08.727  INFO 17284 --- [           main] o.s.b.w.e.u.UndertowServletWebServer     : Undertow started on port(s) 9411 (http) with context path ''
2018-07-20 14:59:08.729  INFO 17284 --- [           main] z.s.ZipkinServer                         : Started ZipkinServer in 4.513 seconds (JVM running for 5.756)
2018-07-20 14:59:36.546  INFO 17284 --- [  XNIO-1 task-1] i.u.servlet                              : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-07-20 14:59:36.547  INFO 17284 --- [  XNIO-1 task-1] o.s.w.s.DispatcherServlet                : FrameworkServlet 'dispatcherServlet': initialization started
2018-07-20 14:59:36.563  INFO 17284 --- [  XNIO-1 task-1] o.s.w.s.DispatcherServlet                : FrameworkServlet 'dispatcherServlet': initialization completed in 15ms

(3)    查看运行效果

        经过上图,咱们发现zipkin使用springboot,而且启动的端口为9411,而后咱们经过浏览器访问,效果以下:

详细参考:https://zipkin.io/pages/quick...

 

6、入门示例

追踪服务包含下面几个服务:

一、注册中心 Eureka Server(可选的,只用于服务生产者和调用者注册)

二、Zipkin服务器

三、服务的生产者及服务的调用者:

1)服务的生产者、调用者是相对的,二者之间能够互相调用,便可以同时做为生产者和调用者,二者都是Eureka Client;

2)二者都要注册到注册中心上,这样才能够相互可见,才能经过服务名来调用指定服务,才能使用Feign或RestTemplate+Ribbon来达到负载均衡

3)二者都要注册到Zipkin服务器上,这样Zipkin才能追踪服务的调用链路

构建工程

基本知识讲解完毕,下面咱们来实战,本文的案例主要有三个工程组成:一个server-zipkin,它的主要做用使用ZipkinServer 的功能,收集调用数据,并展现;一个service-hi,对外暴露hi接口;一个service-miya,对外暴露miya接口;这两个service能够相互调用;而且只有调用了,server-zipkin才会收集数据的,这就是为何叫服务追踪了。

1、Zipkin服务器

代码地址(码云):https://gitee.com/wudiyong/ZipkinServer.git

一、新建一个普通的Spring Boot项目,工程取名为server-zipkin,在其pom引入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dxz.serverzipkin</groupId>
    <artifactId>serverzipkin</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>server-zipkin</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>   <!--配合spring cloud版本 -->
        <relativePath /> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <!--设置字符编码及java版本 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--增长zipkin的依赖 -->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
        </dependency>

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
        </dependency>
        <!--用于测试的,本例可省略 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--依赖管理,用于管理spring-cloud的依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-parent</artifactId>
                <version>Brixton.SR3</version>   <!--官网为Angel.SR4版本,可是我使用的时候老是报错 -->
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <!--使用该插件打包 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2在其程序入口类, 加上注解@EnableZipkinServer,开启ZipkinServer的功能:

package com.dxz.serverzipkin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import zipkin.server.EnableZipkinServer;

@EnableZipkinServer
@SpringBootApplication
public class ServerZipkinApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServerZipkinApplication.class, args);
    }
}

3在配置文件application.yml指定,配置Zipkin服务端口、名称等:

server.port=9411
spring.application.name=my-zipkin-server
启动后打开http://localhost:9411/能够看到
以下图,什么内容都没有,由于尚未任何服务注册到Zipkin,一旦有服务注册到Zipkin便在Service Name下拉列表中能够看到服务名字,当有服务被调用,则能够在Span Name中看到被调用的接口名字.

这里为了测试方便,咱们能够将数据保存到内存中,可是生产环境仍是须要将数据持久化的,原生支持了不少产品,例如ES、数据库等。

二服务生成者调用者

这二者配置是同样的此处简化,直接修改compute-server和feign-consumer两个服务,修改有两点:

一、pom增长

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

二、在其配置文件application.yml指定zipkin server的地址,头经过配置“spring.zipkin.base-url”指定:

spring.zipkin.base-url=http://localhost:9411

至此,能够开始测试Zipkin追踪服务了

 

三启动工程,演示追踪

启动顺序:注册中心(可选)->配置中心(可选)->Zipkin服务器->服务生产者及调用者

咱们能够尝试调用生产者或调用者的接口,而后刷新Zipkin服务器页面,能够看到以下结果:

依次启动上面的三个工程,打开浏览器访问:http://localhost:9411/,会出现如下界面:

再打开http://localhost:9411/的界面,点击Dependencies,能够发现服务的依赖关系:

Paste_Image.png

点击find traces,能够看到具体服务相互调用的数据:

能够看到,调用消费者(ribbon-consumer)耗时83ms,其中消费者调用生产者占了5ms,占比6%。

在测试的过程当中咱们会发现,有时候,程序刚刚启动后,刷新几回,并不能看到任何数据,缘由就是咱们的spring-cloud-sleuth收集信息是有必定的比率的,默认的采样率是0.1,配置此值的方式在配置文件中增长spring.sleuth.sampler.percentage参数配置(若是不配置默认0.1),若是咱们调大此值为1,能够看到信息收集就更及时。可是当这样调整后,咱们会发现咱们的rest接口调用速度比0.1的状况下慢了不少,即便在0.1的采样率下,咱们屡次刷新consumer的接口,会发现对同一个请求两次耗时信息相差很是大,若是取消spring-cloud-sleuth后咱们再测试,会发现并无这种状况,能够看到这种方式追踪服务调用链路会给咱们业务程序性能带来必定的影响。

#sleuth采样率,默认为0.1,值越大收集越及时,但性能影响也越大

spring.sleuth.sampler.percentage=1

 

其实,咱们仔细想一想也能够总结出这种方式的几种缺陷:
缺陷1:zipkin客户端向zipkin-server程序发送数据使用的是http的方式通讯,每次发送的时候涉及到链接和发送过程。
缺陷2:当咱们的zipkin-server程序关闭或者重启过程当中,由于客户端收集信息的发送采用http的方式会被丢失。

针对以上两个明显的缺陷,改进的办法是:
一、通讯采用socket或者其余效率更高的通讯方式。
二、客户端数据的发送尽可能减小业务线程的时间消耗,采用异步等方式发送收集信息。
三、客户端与zipkin-server之间增长缓存类的中间件,例如redis、MQ等,在zipkin-server程序挂掉或重启过程当中,客户端依旧能够正常的发送本身收集的信息。

相信采用以上三种方式会很大的提升咱们的效率和可靠性。其实spring-cloud已经为咱们提供采用MQ或redis等其余的采用socket方式通讯,利用消息中间件或数据库缓存的实现方式。

spring-cloud-sleuth-zipkin-stream方式的实现请看下面内容!

将HTTP通讯改为MQ异步方式通讯

springcloud官方按照传输方式分红了三种启动服务端的方式:

  1. Sleuth with Zipkin via HTTP,
  2. Sleuth with Zipkin via Spring Cloud Stream,
  3. Spring Cloud Sleuth Stream Zipkin Collector。

只须要添加相应的依赖,以后配置相应的注解,如@EnableZipkinStreamServer便可。具体配置参考官方文档:
http://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/1.2.1.RELEASE/#_adding_to_the_project

一、加入依赖

要将http方式改成经过MQ通讯,咱们要将依赖的原来依赖的io.zipkin.java:zipkin-server换成spring-cloud-sleuth-zipkin-stream和spring-cloud-starter-stream-rabbit

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>

 

二、在启动类中开启Stream通讯功能

package com.zipkinServer.ZipkinServer;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer;
import zipkin.server.EnableZipkinServer;
 
/*
* @EnableZipkinServer、@EnableZipkinStreamServer二者二选一
* 经过源码可看到,@EnableZipkinStreamServer包含了@EnableZipkinServer,同时
* 还建立了一个rabbit-mq的消息队列监听器,因此也支持原来的HTTP通讯方式 
*/

//@EnableZipkinServer//默认采用HTTP通讯方式启动ZipkinServer
@EnableZipkinStreamServer//采用Stream通讯方式启动ZipkinServer,也支持HTTP通讯方式
 
@SpringBootApplication
public class ZipkinServerApplication {
 
public static void main(String[] args) {
 
SpringApplication.run(ZipkinServerApplication.class, args);
 
}
 
}

 

三、配置消息中间件rabbit mq地址等信息

#链接rabbitmq服务器配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

 

至此,ZipkinServer配置完成,下面是Zipkin客户端的配置

一、将原来的spring-cloud-starter-zipkin替换为以下依赖便可

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
 
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

 

二、此外,在配置文件中也加上链接MQ的配置

#链接rabbitmq服务器配置
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

至此所有配置完成,能够开始测试。

另外,因为要链接到rabbitmq服务器,因此,还要安装及启动rabbitmq服务器!

加了MQ以后,通讯过程以下图所示:

能够看到以下效果:

1)请求的耗时时间不会出现忽然耗时特长的状况

2)当ZipkinServer不可用时(好比关闭、网络不通等),追踪信息不会丢失,由于这些信息会保存在Rabbitmq服务器上,直到Zipkin服务器可用时,再从Rabbitmq中取出这段时间的信息

持久化到数据库

Zipkin目前只支持mysql数据库,ZipkinServer服务作以下修改,其它服务不需作任何修改

一、加入数据库依赖

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

 

二、在application.properties中配置数据库属性

#zipkin数据保存到数据库中须要进行以下配置
#表示当前程序不使用sleuth
spring.sleuth.enabled=false
#表示zipkin数据存储方式是mysql
zipkin.storage.type=mysql
 
#数据库脚本建立地址,当有多个时可以使用[x]表示集合第几个元素,脚本可到官网下载,须要先手动到数据库执行
spring.datasource.schema[0]=classpath:/zipkin.sql
 
#spring boot数据源配置
spring.datasource.url=jdbc:mysql://localhost:3306/zipkin?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.initialize=true
spring.datasource.continue-on-error=true

 

三、zipkin.sql

数据库脚本文件放到resources目录下,且须要先手动到数据库执行一次,内容以下:

CREATE TABLE IF NOT EXISTS zipkin_spans (
 
`trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
 
`trace_id` BIGINT NOT NULL,
 
`id` BIGINT NOT NULL,
 
`name` VARCHAR(255) NOT NULL,
 
`parent_id` BIGINT,
 
`debug` BIT(1),
 
`start_ts` BIGINT COMMENT 'Span.timestamp(): epoch micros used for endTs query and to implement TTL',
 
`duration` BIGINT COMMENT 'Span.duration(): micros used for minDuration and maxDuration query'
 
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
 
 
 
ALTER TABLE zipkin_spans ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `id`) COMMENT 'ignore insert on duplicate';
 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`, `id`) COMMENT 'for joining with zipkin_annotations';
 
ALTER TABLE zipkin_spans ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTracesByIds';
 
ALTER TABLE zipkin_spans ADD INDEX(`name`) COMMENT 'for getTraces and getSpanNames';
 
ALTER TABLE zipkin_spans ADD INDEX(`start_ts`) COMMENT 'for getTraces ordering and range';
 
 
 
CREATE TABLE IF NOT EXISTS zipkin_annotations (
 
`trace_id_high` BIGINT NOT NULL DEFAULT 0 COMMENT 'If non zero, this means the trace uses 128 bit traceIds instead of 64 bit',
 
`trace_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.trace_id',
 
`span_id` BIGINT NOT NULL COMMENT 'coincides with zipkin_spans.id',
 
`a_key` VARCHAR(255) NOT NULL COMMENT 'BinaryAnnotation.key or Annotation.value if type == -1',
 
`a_value` BLOB COMMENT 'BinaryAnnotation.value(), which must be smaller than 64KB',
 
`a_type` INT NOT NULL COMMENT 'BinaryAnnotation.type() or -1 if Annotation',
 
`a_timestamp` BIGINT COMMENT 'Used to implement TTL; Annotation.timestamp or zipkin_spans.timestamp',
 
`endpoint_ipv4` INT COMMENT 'Null when Binary/Annotation.endpoint is null',
 
`endpoint_ipv6` BINARY(16) COMMENT 'Null when Binary/Annotation.endpoint is null, or no IPv6 address',
 
`endpoint_port` SMALLINT COMMENT 'Null when Binary/Annotation.endpoint is null',
 
`endpoint_service_name` VARCHAR(255) COMMENT 'Null when Binary/Annotation.endpoint is null'
 
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
 
 
 
ALTER TABLE zipkin_annotations ADD UNIQUE KEY(`trace_id_high`, `trace_id`, `span_id`, `a_key`, `a_timestamp`) COMMENT 'Ignore insert on duplicate';
 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`, `span_id`) COMMENT 'for joining with zipkin_spans';
 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id_high`, `trace_id`) COMMENT 'for getTraces/ByIds';
 
ALTER TABLE zipkin_annotations ADD INDEX(`endpoint_service_name`) COMMENT 'for getTraces and getServiceNames';
 
ALTER TABLE zipkin_annotations ADD INDEX(`a_type`) COMMENT 'for getTraces';
 
ALTER TABLE zipkin_annotations ADD INDEX(`a_key`) COMMENT 'for getTraces';
 
ALTER TABLE zipkin_annotations ADD INDEX(`trace_id`, `span_id`, `a_key`) COMMENT 'for dependencies job';
 
 
 
CREATE TABLE IF NOT EXISTS zipkin_dependencies (
 
`day` DATE NOT NULL,
 
`parent` VARCHAR(255) NOT NULL,
 
`child` VARCHAR(255) NOT NULL,
 
`call_count` BIGINT
 
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED CHARACTER SET=utf8 COLLATE utf8_general_ci;
 
 
 
ALTER TABLE zipkin_dependencies ADD UNIQUE KEY(`day`, `parent`, `child`);

 

至此,ZipkinServer采用数据库存储配置完成。

测试时发现,要用MQ异步方式通讯的pom.xml配置及@EnableZipkinStreamServer注解才能够(@EnableZipkinServer貌似只能保存到内存),不然启动报错,不明白为何。

elasticsearch存储

前面讲了利用mq的方式发送数据,存储在mysql,实际生产过程当中调用数据量很是的大,mysql存储并非很好的选择,这时咱们能够采用elasticsearch进行存储

配置过程也很简单

一、mysql依赖改为elasticsearch依赖

<!-- 添加 spring-data-elasticsearch的依赖 -->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId>
<version>1.24.0</version>
<optional>true</optional>
</dependency>

 

二、数据库配置改为elasticsearch配置

#表示当前程序不使用sleuth
spring.sleuth.enabled=false
#表示zipkin数据存储方式是elasticsearch
zipkin.storage.StorageComponent = elasticsearch
zipkin.storage.type=elasticsearch
zipkin.storage.elasticsearch.cluster=elasticsearch-zipkin-cluster
zipkin.storage.elasticsearch.hosts=127.0.0.1:9300
# zipkin.storage.elasticsearch.pipeline=
zipkin.storage.elasticsearch.max-requests=64
zipkin.storage.elasticsearch.index=zipkin
zipkin.storage.elasticsearch.index-shards=5
zipkin.storage.elasticsearch.index-replicas=1

三、安装elasticsearch

其它代码彻底不变

具体见:

http://www.cnblogs.com/shunyang/p/7011306.html

http://www.cnblogs.com/shunyang/p/7298005.html

https://segmentfault.com/a/1190000012342007

https://blog.csdn.net/meiliangdeng1990/article/details/54131384

相关文章
相关标签/搜索