微服务实战系列之SpringCloud Alibaba学习(四)

微服务实战系列之SpringCloud Alibaba:

  • 微服务实战系列之SpringCloud Alibaba学习(一)
  • 微服务实战系列之SpringCloud Alibaba学习(二)
  • 微服务实战系列之SpringCloud Alibaba学习(三)
  • 微服务实战系列之SpringCloud Alibaba学习(四)

在微服务实战系列之SpringCloud Alibaba学习(一)中,学习了搭建三大微服务并完成交互开发与测试。

在微服务实战系列之SpringCloud Alibaba学习(二)中,针对微服务会遇到的一些问题,使用了一些微服务组件来解决,实现了用户微服务、商品微服务和订单微服务之间的远程调用,并且实现了服务调用的负载均衡。也基于阿里开源的Sentinel实现了服务的限流与容错,并详细介绍了Sentinel的核心技术与配置规则 。如下:

  • 使用Nacos来实现服务的注册与发现
  • 使用Ribbon来实现服务调用的负载均衡
  • 使用Sentinel实现接口限流

在微服务实战系列之SpringCloud Alibaba学习(三)中,简单介绍了服务网关,并对SpringCloud Gateway的核心架构进行了简要说明,也在项目中整合了SpringCloud Gateway网关实现了通过网关访问后端微服务,另外,也基于SpringCloud Gateway整合Sentinel实现了网关的限流功能。

  • 使用SpringCloud Gateway网关实现了通过网关访问后端微服务以及限流功能

在微服务实战系列之SpringCloud Alibaba学习(四)中,正式学习分布式链路追踪技术与解决方案

文章目录

      • 1. 分布式链路追踪
        • 1.1 基本知识
        • 1.2 核心原理
        • 1.3 解决方案
      • 2. 项目整合Sleuth实现链路追踪
        • 2.1 Sleuth概述
        • 2.2 项目整合Sleuth
        • 2.3 抽样采集数据
        • 2.4 追踪自定义线程池
        • 2.5 演示使用@Async注解开启任务
        • 2.6 演示自定义任务线程池
        • 2.7 演示包装自定义线程池
      • 3. Sleuth整合ZipKin
        • 3.1 ZipKin核心架构
          • 3.1.1 ZipKin概述
          • 3.1.2 ZipKin核心架构
        • 3.2 项目整合ZipKin
          • 3.2.1 下载安装ZipKin服务端
          • 3.2.2 项目整合ZipKin客户端
        • 3.3 ZipKin数据持久化
          • 3.3.1 ZipKin数据持久化到MySQL
          • 3.3.2 ZipKin数据持久化到ElasticSearch

1. 分布式链路追踪

1.1 基本知识

随着互联网业务快速扩展,企业的业务系统变得越来越复杂,不少企业开始向分布式、微服务方向发展,将原本的单体应用拆分成分布式、微服务。这也使得当客户端请求系统的接口时,原本在同一个系统内部的请求逻辑变成了需要在多个微服务之间流转的请求。

单体架构中可以使用AOP在调用具体的业务逻辑前后分别打印一下时间即可计算出整体的调用时间,使用 AOP捕获异常也可知道是哪里的调用导致的异常。

但是在分布式微服务场景下,使用AOP技术是无法追踪到各个微服务的调用情况的,也就无法知道系统中处理一次请求的整体调用链路。

另外,在分布式与微服务场景下,我们需要解决如下问题:

  • 如何快速发现并定位到分布式系统中的问题。
  • 如何尽可能精确的判断故障对系统的影响范围与影响程度。
  • 如何尽可能精确的梳理出服务之间的依赖关系,并判断出服务之间的依赖关系是否合理。
  • 如何尽可能精确的分析整个系统调用链路的性能与瓶颈点。
  • 如何尽可能精确的分析系统的存储瓶颈与容量规划。
  • 如何实时观测系统的整体调用链路情况。

上述问题就是分布式链路追踪技术要解决的问题。所谓的分布式链路追踪,就是将对分布式系统的一次请求转化成一个完整的调用链路。这个完整的调用链路从请求进入分布式系统的入口开始,直到整个请求返回为止。并在请求调用微服务的过程中,记录相应的调用日志,监控系统调用的性能,并且可以按照某种方式显示请求调用的情况

在分布式链路追踪中,可以统计调用每个微服务的耗时,请求会经过哪些微服务的流转,每个微服务的运行状况等信息。

1.2 核心原理

假定三个微服务调用的链路如下图所示:Service 1 调用 Service 2,Service 2 调用 Service 3 和 Service 4。

微服务实战系列之SpringCloud Alibaba学习(四)_第1张图片
那么链路追踪会在每个服务调用的时候加上 Trace ID 和 Span ID。如下图所示:

微服务实战系列之SpringCloud Alibaba学习(四)_第2张图片
小伙伴注意上面的颜色,相同颜色的代表是同一个 Span ID,说明是链路追踪中的一个节点。

  • 第一步:用户端调用 Service 1,生成一个 Request,Trace ID 和 Span ID 为空,那个时候请求还没有到
    Service 1。
  • 第二步:请求到达 Service 1,记录了 Trace ID = X,Span ID 等于 A。
  • 第三步:Service 1 发送请求给 Service 2,Span ID 等于 B,被称作 Client Sent,即用户端发送一个请求。
  • 第四步:请求到达 Service 2,Span ID 等于 B,Trace ID 不会改变,被称作 Server Received,即服务端取得请求并准备开始解决它。
  • 第五步:Service 2 开始解决这个请求,解决完之后,Trace ID 不变,Span ID = C。
  • 第六步:Service 2 开始发送这个请求给 Service 3,Trace ID 不变,Span ID = D,被称作 Client Sent,即用户端发送一个请求。
  • 第七步:Service 3 接收到这个请求,Span ID = D,被称作 Server Received。
  • 第八步:Service 3 开始解决这个请求,解决完之后,Span ID = E。
  • 第九步:Service 3 开始发送响应给 Service 2,Span ID = D,被称作 Server Sent,即服务端发送响应。
  • 第十步:Service 3 收到 Service 2 的响应,Span ID = D,被称作 Client Received,即用户端接收响应。
  • 第十一步:Service 2 开始返回 响应给 Service 1,Span ID = B,和第三步的 Span ID 相同,被称作 Client Received,即用户端接收响应。
  • 第十二步:Service 1 解决完响应,Span ID = A,和第二步的 Span ID 相同。
  • 第十三步:Service 1 开始向用户端返回响应,Span ID = A、Service 3 向 Service 4 发送请求和 Service 3 相似,对应的 Span ID 是 F 和 G。可以参照上面前面的第六步到第十步。

把以上的相同颜色的步骤简化为下面的链路追踪图:
微服务实战系列之SpringCloud Alibaba学习(四)_第3张图片

  • 第一个节点:Span ID = A,Parent ID = null,Service 1 接收到请求。
  • 第二个节点:Span ID = B,Parent ID= A,Service 1 发送请求到 Service 2 返回响应给Service 1 的过程。
  • 第三个节点:Span ID = C,Parent ID= B,Service 2 的 中间解决过程。
  • 第四个节点:Span ID = D,Parent ID= C,Service 2 发送请求到 Service 3 返回响应给Service 2 的过程。
  • 第五个节点:Span ID = E,Parent ID= D,Service 3 的中间解决过程。
  • 第六个节点:Span ID = F,Parent ID= C,Service 3 发送请求到 Service 4 返回响应给 Service 3 的过程。
  • 第七个节点:Span ID = G,Parent ID= F,Service 4 的中间解决过程。

通过 Parent ID 就可找到父节点,整个链路即可以进行跟踪追溯了。

1.3 解决方案

目前,行业内比较成熟的分布式链路追踪技术解决方案如下所示。
微服务实战系列之SpringCloud Alibaba学习(四)_第4张图片
微服务实战系列之SpringCloud Alibaba学习中,我们会使用 Sleuth+ZipKin的方案实现分布式链路追踪。

2. 项目整合Sleuth实现链路追踪

2.1 Sleuth概述

Sleuth是SpringCloud中提供的一个分布式链路追踪组件,在设计上大量参考并借用了Google Dapper的设计。

Span简介

Span在Sleuth中代表一组基本的工作单元,当请求到达各个微服务时,Sleuth会通过一个唯一的标识,也就是SpanId来标记开始通过这个微服务,在当前微服务中执行的具体过程和执行结束。

此时,通过SpanId标记的开始时间戳和结束时间戳,就能够统计到当前Span的调用时间,也就是当前微服务的执行时间。另外,也可以用过Span获取到事件的名称,请求的信息等数据。

总结:远程调用和Span是一对一的关系,是分布式链路追踪中最基本的工作单元,每次发送一个远程调用服务就会产生一个 Span。Span Id 是一个 64 位的唯一 ID,通过计算 Span 的开始和结束时间,就可以统计每个服务调用所耗费的时间。

Trace简介

Trace的粒度比Span的粒度大,Trace主要是由具有一组相同的Trace ID的Span组成的,从请求进入分布式系统入口经过调用各个微服务直到返回的整个过程,都是一个Trace。

也就是说,当请求到达分布式系统的入口时,Sleuth会为请求创建一个唯一标识,这个唯一标识就是Trace Id,不管这个请求在分布式系统中如何流转,也不管这个请求在分布式系统中调用了多少个微服务,这个Trace Id都是不变的,直到整个请求返回。

总结:一个 Trace 可以对应多个 Span,Trace和Span是一对多的关系。Trace Id是一个64 位的唯一ID。Trace Id可以将进入分布式系统入口经过调用各个微服务,再到返回的整个过程的请求串联起来,内部每通过一次微服务时,都会生成一个新的SpanId。Trace串联了整个请求链路,而Span在请求链路中区分了每个微服务。

Annotation简介

Annotation记录了一段时间内的事件,内部使用的重要注解如下所示。

  • cs(Client Send)客户端发出请求,标记整个请求的开始时间。
  • sr(Server Received)服务端收到请求开始进行处理,通过sr与cs可以计算网络的延迟时间,例如:sr- cs = 网络延迟(服务调用的时间)。
  • ss(Server Send)服务端处理完毕准备将结果返回给客户端, 通过ss与sr可以计算服务器上的请求处理时间,例如:ss - sr = 服务器上的请求处理时间。
  • cr(Client Reveived)客户端收到服务端的响应,请求结束。通过cr与cs可以计算请求的总时间,例如:cr - cs = 请求的总时间。

总结:链路追踪系统内部定义了少量核心注解,用来定义一个请求的开始和结束,通过这些注解,我们可以计算出请求的每个阶段的时间。需要注解的是,这里说的请求,是在系统内部流转的请求,而不是从浏览器、APP、H5、小程序等发出的请求。

2.2 项目整合Sleuth

Sleuth提供了分布式链路追踪能力,如果需要使用Sleuth的链路追踪功能,需要在项目中集成Sleuth。

最简使用

(1)在每个微服务(用户微服务shop-user、商品微服务shop-product、订单微服务shop-order、网关服务shop-gateway)下的pom.xml文件中添加如下Sleuth的依赖。

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

(2)将项目的application.yml文件备份成application-pre-filter.yml,并将application.yml文件的内容替换为application-sentinel.yml文件的内容,这一步是为了让整个项目集成Sentinel、SpringCloud Gateway和Nacos。application.yml替换后的文件内容如下所示。

server:
  port: 10002
spring:
  application:
    name: server-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        port: 7777
        dashboard: 127.0.0.1:8888
      web-context-unify: false
      eager: true

    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowCredentials: true
            allowedHeaders: "*"
      discovery:
        locator:
          enabled: true
          route-id-prefix: gateway-

(3)分别启动Nacos、Sentinel、用户微服务shop-user,商品微服务shop-product,订单微服务shop-order和网关服务shop-gateway,在浏览器中输入链接localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如下所示。
在这里插入图片描述
(4)分别查看用户微服务shop-user,商品微服务shop-product,订单微服务shop-order和网关服务shop-gateway的控制台输出,每个服务的控制台都输出了如下格式所示的信息。

[微服务名称,TraceID,SpanID,是否将结果输出到第三方平台]

具体如下所示。

  • 用户微服务shop-user
[server-user,03fef3d312450828,76b298dba54ec579,true]
  • 商品微服务shop-product
[server-product,03fef3d312450828,41ac8836d2df4eec,true]
[server-product,03fef3d312450828,6b7b3662d63372bf,true]
  • 订单微服务shop-order
[server-order,03fef3d312450828,cbd935d57cae84f9,true]
  • 网关服务shop-gateway
[server-gateway,03fef3d312450828,03fef3d312450828,true]

可以看到,每个服务都打印出了链路追踪的日志信息,说明引入Sleuth的依赖后,就可以在命令行查看链路追踪情况。

2.3 抽样采集数据

Sleuth支持抽样采集数据。尤其是在高并发场景下,如果采集所有的数据,那么采集的数据量就太大了,非常耗费系统的性能。通常的做法是可以减少一部分数据量,特别是对于采用Http方式去发送采集数据,能够提升很大的性能。

Sleuth可以采用如下方式配置抽样采集数据。

spring:
  sleuth:
    sampler:
      probability: 1.0

2.4 追踪自定义线程池

Sleuth支持对异步任务的链路追踪,在项目中使用@Async注解开启一个异步任务后,Sleuth会为异步任务重新生成一个Span。但是如果使用了自定义的异步任务线程池,则会导致Sleuth无法新创建一个Span,而是会重新生成Trace和Span。此时,需要使用Sleuth提供的LazyTraceExecutor类来包装下异步任务线程池,才能在异步任务调用链路中重新创建Span。

在服务中开启异步线程池任务,需要使用@EnableAsync。所以,在演示示例前,先在用户微服务shop-user的io.binghe.shop.UserStarter启动类上添加@EnableAsync注解,如下所示。

/**
 * @description 启动用户服的类
 */
@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan(value = { "io.binghe.shop.user.mapper" })
@EnableDiscoveryClient
@EnableAsync
public class UserStarter {
    public static void main(String[] args){
        SpringApplication.run(UserStarter.class, args);
    }
}

2.5 演示使用@Async注解开启任务

(1)在用户微服务shop-user的io.binghe.shop.user.service.UserService接口中定义一个asyncMethod()方法,如下所示。

void asyncMethod();

(2)在用户微服务shop-user的io.binghe.shop.user.service.impl.UserServiceImpl类中实现asyncMethod()方法,并在asyncMethod()方法上添加@Async注解,如下所示。

@Async
@Override
public void asyncMethod() {
    log.info("执行了异步任务...");
}

(3)在用户微服务shop-user的io.binghe.shop.user.controller.UserController类中新增asyncApi()方法,如下所示。

@GetMapping(value = "/async/api")
public String asyncApi() {
    log.info("执行异步任务开始...");
    userService.asyncMethod();
    log.info("异步任务执行结束...");
    return "asyncApi";
}

(4)分别启动用户微服务和网关服务,在浏览器中输入链接http://localhost:10001/server-user/user/async/api

图片

(5)查看用户微服务与网关服务的控制台日志,分别存在如下日志。

  • 用户微服务
[server-user,499d6c7128399ed0,a81bd920de0b07de,true]执行异步任务开始...
[server-user,499d6c7128399ed0,a81bd920de0b07de,true]异步任务执行结束...
[server-user,499d6c7128399ed0,e2f297d512f40bb8,true]执行了异步任务...
  • 网关服务
[server-gateway,499d6c7128399ed0,499d6c7128399ed0,true]

可以看到Sleuth为异步任务重新生成了Span。

2.6 演示自定义任务线程池

在演示使用@Async注解开启任务的基础上继续演示自定义任务线程池,验证Sleuth是否为自定义线程池新创建了Span。

(1)在用户微服务shop-user中新建io.binghe.shop.user.config包,在包下创建ThreadPoolTaskExecutorConfig类,继承org.springframework.scheduling.annotation.AsyncConfigurerSupport类,用来自定义异步任务线程池,代码如下所示。

/**
 * @description Sleuth异步线程池配置
 */
@Configuration
@EnableAutoConfiguration
public class ThreadPoolTaskExecutorConfig extends AsyncConfigurerSupport {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("trace-thread-");
        executor.initialize();
        return executor;
    }
}

(2)以debug的形式启动用户微服务和网关服务,并在io.binghe.shop.user.config.ThreadPoolTaskExecutorConfig#getAsyncExecutor()方法中打上断点,如下所示。

微服务实战系列之SpringCloud Alibaba学习(四)_第5张图片
可以看到,项目启动后并没有进入io.binghe.shop.user.config.ThreadPoolTaskExecutorConfig#getAsyncExecutor()方法,说明项目启动时,并不会创建异步任务线程池。

(3)在浏览器中输入链接http://localhost:10001/server-user/user/async/api,此时可以看到程序已经执行到io.binghe.shop.user.config.ThreadPoolTaskExecutorConfig#getAsyncExecutor()方法的断点位置。
微服务实战系列之SpringCloud Alibaba学习(四)_第6张图片
说明异步任务线程池是在调用了异步任务的时候创建的。

接下来,按F8跳过断点继续运行程序,可以看到浏览器上的显示结果如下。

在这里插入图片描述
(4)查看用户微服务与网关服务的控制台日志,分别存在如下日志。

  • 用户微服务
[server-user,f89f2355ec3f9df1,4d679555674e96a4,true]执行异步任务开始...
[server-user,f89f2355ec3f9df1,4d679555674e96a4,true]异步任务执行结束...
[server-user,0ee48d47e58e2a42,0ee48d47e58e2a42,true]执行了异步任务...
  • 网关服务
[server-gateway,f89f2355ec3f9df1,f89f2355ec3f9df1,true]

可以看到,使用自定义异步任务线程池时,在用户微服务中在执行异步任务时,重新生成了Trace和Span。

注意对比用户微服务中输出的三条日志信息,最后一条日志信息的TraceID和SpanID与前两条日志都不同。

2.7 演示包装自定义线程池

在自定义任务线程池的基础上继续演示包装自定义线程池,验证Sleuth是否为包装后的自定义线程池新创建了Span。

(1)在用户微服务shop-user的io.binghe.shop.user.config.ThreadPoolTaskExecutorConfig类中注入BeanFactory,并在getAsyncExecutor()方法中使用org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor()来包装返回的异步任务线程池,修改后的io.binghe.shop.user.config.ThreadPoolTaskExecutorConfig类的代码如下所示。

/**
 * @description Sleuth异步线程池配置
 */
@Configuration
@EnableAutoConfiguration
public class ThreadPoolTaskExecutorConfig extends AsyncConfigurerSupport {

    @Autowired
    private BeanFactory beanFactory;

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("trace-thread-");
        executor.initialize();
        return new LazyTraceExecutor(this.beanFactory, executor);
    }
}

(2)分别启动用户微服务和网关服务,在浏览器中输入链接http://localhost:10001/server-user/user/async/api

图片

(3)查看用户微服务与网关服务的控制台日志,分别存在如下日志。

  • 用户微服务
[server-user,157891cb90fddb65,0a278842776b1f01,true]执行异步任务开始...
[server-user,157891cb90fddb65,0a278842776b1f01,true]异步任务执行结束...
[server-user,157891cb90fddb65,1ba55fd3432b77ae,true]执行了异步任务...
  • 网关服务
[server-gateway,157891cb90fddb65,157891cb90fddb65,true]

可以看到Sleuth为异步任务重新生成了Span。

综上说明:Sleuth支持对异步任务的链路追踪,在项目中使用@Async注解开启一个异步任务后,Sleuth会为异步任务重新生成一个Span。但是如果使用了自定义的异步任务线程池,则会导致Sleuth无法新创建一个Span,而是会重新生成Trace和Span。此时,需要使用Sleuth提供的LazyTraceExecutor类来包装下异步任务线程池,才能在异步任务调用链路中重新创建Span。

3. Sleuth整合ZipKin

在前面整合Sleuth实现链路追踪时,我们是通过查看日志的情况来了解系统调用的链路情况,这并不是一种很好的解决方案,如果系统所包含的微服务越来越多,通过查看日志的方式来分析系统的调用是非常复杂的,在实际项目中根本不可行。此时,我们可以将Sleuth和ZipKin进行整合,利用ZipKin将日志进行聚合,将链路日志进行可视化展示,并支持全文检索

3.1 ZipKin核心架构

Zipkin 是 Twitter 的一个开源项目,它基于Google Dapper论文实现,可以收集微服务运行过程中的实时链路数据,并进行展示。

3.1.1 ZipKin概述

Zipkin是一种分布式链路跟踪系统,能够收集微服务运行过程中的实时调用链路信息,并能够将这些调用链路信息展示到Web界面上供开发人员分析,开发人员能够从ZipKin中分析出调用链路中的性能瓶颈,识别出存在问题的应用程序,进而定位问题和解决问题。

3.1.2 ZipKin核心架构

ZipKin的核心架构图如下所示。
微服务实战系列之SpringCloud Alibaba学习(四)_第7张图片

其中,ZipKin核心组件的功能如下所示。

  • Reporter:ZipKin中上报链路数据的模块,主要配置在具体的微服务应用中。
  • Transport:ZipKin中传输链路数据的模块,此模块可以配置为Kafka,RocketMQ、RabbitMQ等。
  • Collector:ZipKin中收集并消费链路数据的模块,默认是通过http协议收集,可以配置为Kafka消费。
  • Storage:ZipKin中存储链路数据的模块,此模块的具体可以配置为ElasticSearch、Cassandra或者MySQL,目前ZipKin支持这三种数据持久化方式。
  • API:ZipKin中的API 组件,主要用来提供外部访问接口。比如给客户端展示跟踪信息,或是开放给外部系统实现监控等。
  • UI:ZipKin中的UI 组件,基于API组件实现的上层应用。通过UI组件用户可以方便并且很直观地查询和分析跟踪信息。

Zipkin在总体上会分为两个端,一个是Zipkin服务端,一个是Zipkin客户端,客户端主要是配置在微服务应用中,收集微服务中的调用链路信息,将数据发送给ZipKin服务端。

3.2 项目整合ZipKin

Zipkin总体上分为服务端和客户端,我们需要下载并启动ZipKin服务端的Jar包,在微服务中集成ZipKin的客户端。

3.2.1 下载安装ZipKin服务端

(1)下载ZipKin服务端Jar文件,可以直接在浏览器中输入如下链接进行下载。

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

如果大家使用的是Linux操作系统,也可以在命令行输入如下命令进行下载。

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

这里,我通过浏览器下载的ZipKin服务端Jar文件为:zipkin-server-2.12.9-exec.jar。

(2)在命令行输入如下命令启动ZipKin服务端。

java -jar zipkin-server-2.12.9-exec.jar

(3)由于ZipKin服务端启动时,默认监听的端口号为9411,所以,在浏览器中输入http://localhost:9411链接就可以打开ZipKin的界面,如下所示。
微服务实战系列之SpringCloud Alibaba学习(四)_第8张图片在浏览器中输入http://localhost:9411链接能够打开上述页面就说明ZipKin服务端已经准备好啦。

3.2.2 项目整合ZipKin客户端

(1)在每个微服务(用户微服务shop-user,商品微服务shop-product,订单微服务shop-order,网关服务shop-gateway)中添加ZipKin依赖,如下所示。

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

(2)在网关服务shop-gateway的application.yml文件中添加如下配置。

spring:
  sleuth:
    sampler:
      probability: 1.0
  zipkin:
    base-url: http://127.0.0.1:9411
    discovery-client-enabled: false

其中各配置的说明如下所示。

spring.sleuth.sampler.probability:表示Sleuth的采样百分比。
spring.zipkin.base-url:ZipKin服务端的地址。
spring.zipkin.discovery-client-enabled:配置成false,使Nacos将其当成一个URL,不要按服务名处理。

(3)分别启动用户微服务,商品微服务,订单微服务和服务网关,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如下所示。

图片

3.3 ZipKin数据持久化

我们实现了在项目中集成ZipKin,但是此时我们集成ZipKin后,ZipKin中的数据是保存在系统内存中的,如果我们重启了ZipKin,则保存在系统内存中的数据就会丢失,那我如何避免数据丢失呢?ZipKin支持将数据进行持久化来防止数据丢失,可以将数据保存到ElasticSearch、Cassandra或者MySQL中。这里,我们重点介绍下如何将数据保存到MySQL和ElasticSearch中。

3.3.1 ZipKin数据持久化到MySQL

(1)将Zipkin数据持久化到MySQL,我们需要知道MySQL的数据表结构,好在ZipKin提供了MySQL脚本,小伙伴们可以在链接:https://github.com/openzipkin/zipkin/tree/master/zipkin-storage里面下载。
微服务实战系列之SpringCloud Alibaba学习(四)_第9张图片当然,我将下载后的MySQL脚本放到了网关服务shop-gateway的resources目录下的scripts目录下。

微服务实战系列之SpringCloud Alibaba学习(四)_第10张图片
(2)在MySQL数据库中新建zipkin数据库,如下所示。

create database if not exists zipkin;

(3)在新建的数据库zipkin中运行mysql.sql脚本,运行脚本后的效果如下所示。
微服务实战系列之SpringCloud Alibaba学习(四)_第11张图片
可以看到,在zipkin数据库中新建了zipkin_annotations、zipkin_dependencies和zipkin_spans三张数据表。

(4)启动ZipKin时指定MySQL数据源,如下所示。

java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=mysql --MYSQL_HOST=127.0.0.1 --MYSQL_TCP_PORT=3306 --MYSQL_DB=zipkin --MYSQL_USER=root --MYSQL_PASS=root

(5)启动ZipKin后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如下所示。
在这里插入图片描述(6)查看zipkin数据库中的数据,发现zipkin_annotations数据表与zipkin_spans数据表已经存在系统的调用链路数据。

  • zipkin_annotations数据表部分数据如下所示。
    微服务实战系列之SpringCloud Alibaba学习(四)_第12张图片
  • zipkin_spans数据表部分数据如下所示。
    在这里插入图片描述可以看到,ZipKin已经将数据持久化到MySQL中,重启ZipKin后就会从MySQL中读取数据,数据也不会丢失了。
3.3.2 ZipKin数据持久化到ElasticSearch

(1)到ElasticSearch官网下载ElasticSearch,链接为:

https://www.elastic.co/cn/downloads/elasticsearch。

这里下载的安装包是:elasticsearch-8.2.0-windows-x86_64.zip。

(2)解压elasticsearch-8.2.0-windows-x86_64.zip,在解压后的bin目录下找到elasticsearch.bat脚本,双击运行ElasticSearch。

(3)启动ZipKin服务端时,指定ElasticSearch,如下所示。

java -jar zipkin-server-2.12.9-exec.jar --STORAGE_TYPE=elasticsearch --ESHOST=localhost:9200

(4)启动ZipKin服务端后,在浏览器中访问链接http://localhost:10001/server-order/order/submit_order?userId=1001&productId=1001&count=1,如下所示。

图片
ZipKin就会将请求的链路信息保存到ElasticSearch中进行持久化。

参考:

本文是参考冰河技术得SpringCloud Alibaba实战专栏内容整理的,只是方便学习使用(侵权删),具体想要了解或想要获取源码的,请参考下面冰河技术的链接,关注公众号获取源码。

SpringCloud Alibaba

冰河技术:《SpringCloud Alibaba实战》

你可能感兴趣的:(SpringCloud,Allibaba,spring,cloud,微服务,学习)