SpringCloud学习笔记(八)——使用Spring Cloud Sleuth跟踪微服务

简介

在微服务数量较多的系统架构中,一个完整的HTTP请求可能需要经过好几个微服务。如果想要跟踪一条完整的HTTP请求链路所产生的日志,我们需要到各个微服务上去查看日志并检索出我们需要的信息。随着业务发展,微服务的数量也会越来越多,这个过程也变得愈发困难。不过不用担心,Spring Cloud Sleuth为我们提供了分布式服务跟踪的解决方案。为了演示如何使用Spring Cloud Sleuth,我们需要构建一个小型的微服务系统。

准备工作

这里我们需要创建两个微服务Server-Provider1和Server-Provider2,它们都具有一个名为hello的REST接口,Server-Provider1的hello接口依赖于Server-Provider2的hello接口。并将这两个服务注册到Eureka-Server服务注册中心集群。

  1. 创建Server-Provider1
    新建一个Spring Boot工程,artifactId为Server-Provider1,并引入如下依赖:

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    

    spring-cloud-starter-eureka用于注册微服务,spring-cloud-starter-ribbon用于调用Server-Provider2提供的服务,spring-cloud-starter-sleuth为Spring Cloud Sleuth依赖,用于跟踪微服务请求。

    接着在配置文件application.yml里添加如下配置:

    spring:
      application:
        name: server-provider1
    server:
      port: 8100
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8085/eureka, http://localhost:8087/eureka
    

    然后我们在入口类中添加@EnableDiscoveryClient注解,开启服务的注册与发现。并且注册RestTemplate,用于Ribbon服务远程调用:

    @EnableDiscoveryClient
    @SpringBootApplication
    public class SleuthdemoApplication {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(SleuthdemoApplication.class, args);
        }
    
    }
    

    最后编写REST接口:

    @RestController
    @RequestMapping("hello")
    public class HelloController {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping
        public String hello() {
            logger.info("调用server-provider1的hello接口");
            return this.restTemplate.getForEntity("http://server-provider2/hello", String.class).getBody();
        }
    }
    

    在hello接口中,我们通过RestTemplate远程调用了server-provider2的hello接口。

  2. 创建Server-Provider2
    步骤与Server-Provider1一致,只需要修改rest的部分

    @RestController
    @RequestMapping("hello")
    public class HelloController {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        @GetMapping
        public String hello() {
            logger.info("调用server-provider2的hello接口");
            return "hello world";
        }
    }
    
  3. 测试Spring Cloud Sleuth
    启动Eureka-Server集群,然后分别启动Server-Provider1和Server-Provider2。
    可见服务都启动成功了,我们往Server-provider1发送http://localhost:8100/hello请求。
    然后观察各自的日志:

    Server-Provider1:

    2018-06-25 10:13:40.921  INFO [server-provider1,939ca3c1d060ed40,939ca3c1d060ed40,false] 12516 --- [nio-9000-exec-6] c.e.demo.controller.HelloController      : 调用server-provider1的hello接口
    

    Server-Provider2:

    2018-06-25 10:13:40.931  INFO [server-provider2,939ca3c1d060ed40,3f31114e88154074,false] 6500 --- 
    

    可以看到,日志里出现了[server-provider2,939ca3c1d060ed40,3f31114e88154074,false]信息,这些信息由Spring Cloud Sleuth生成,用于跟踪微服务请求链路。这些信息包含了4个部分的值,它们的含义如下:

    1. server-provider2微服务的名称,与spring.application.name对应;
    2. 939ca3c1d060ed40称为Trace ID,在一条完整的请求链路中,这个值是固定的。观察上面的日志即可证实这一点;
    3. 3f31114e88154074称为Span ID,它表示一个基本的工作单元;
    4. false表示是否要将该信息输出到Zipkin等服务中来收集和展示,这里我们还没有集成Zipkin,所以为false。

集成Zipkin

虽然我们已经可以通过Trace ID来跟踪整体请求链路了,但是我们还是得去各个系统中捞取日志。在并发较高得时候,日志是海量的,这个时候我们可以借助Zipkin来代替我们完成日志获取与分析。Zipkin是Twitter的一个开源项目,主要包含了以下四个组件:

  1. Collector:收集器,负责收集日志信息,以供后续的存储,分析与展示;
  2. Storage:存储模块,我们可以通过它将日志存储到MySQL中;
  3. RESTful API:API组件,它主要用来提供外部访问接口。 比如给客户端展示跟踪信息,或是外接系统访问以实现监控等;
  4. WEB UI:通过web页面,我们可以轻松的分析与跟踪请求日志。
搭建Zipkin-Server

在完成Spring Cloud Cleuth与Zipkin的整合之前,我们需要搭建一个Zipkin服务。
新建一个Spring Boot应用,并引入如下依赖:

	<properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
        <zipkin.version>2.11.8</zipkin.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
            <version>${zipkin.version}</version>
            #如果不去除依赖,启动时会报错
            <exclusions>
                <exclusion>
                    <groupId>org.apache.logging.log4j</groupId>
                    <artifactId>log4j-slf4j-impl</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
            <version>${zipkin.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

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

        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
            <version>${zipkin.version}</version>
        </dependency>

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

在入口类中添加@EnableZipkinServer注解,用于启动Zipkin服务。

接着在application.yml中添加如下配置:

server:
  port: 8102
spring:
  application:
    name: zipkin-server
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8085/eureka, http://localhost:8087/eureka
management:
  metrics:
    web:
      server:
        auto-time-requests: false

启动项目,访问http://localhost:8102

微服务引入Zipkin

接着我们需要在Server-Provider1和Server-Provider2里引入Zipkin服务。

分别在Server-Provider1和Server-Provider2里添加Zipkin相关依赖:

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

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

然后分别在Server-Provider1和Server-Provider2的配置文件里添加Zipkin服务地址:

spring:
  application:
    name: server-provider1
  zipkin:
    base-url: http://localhost:8102
    enabled: true
    locator:
      discovery:
        enabled: true
    sender:
      type: WEB
  #sleuth配置
  sleuth:
    web:
      client:
        enabled: true
    sampler:
      #默认的采样比率为0.1,不能看到所有请求数据
      #更改采样比率为1,就能看到所有的请求数据了,但是这样会增加接口调用延迟
      probability: 1.0
server:
  port: 8100
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8085/eureka, http://localhost:8087/eureka

不配置这个,zipkin服务端那边接收不到实例
spring.zipkin.locator.discovery.enabled=true
spring.zipkin.locator.sender.type=WEB

数据存储

这些跟踪信息在Zipkin-Server服务重启后便会丢失,我们可以将这些信息存储到MySQL数据库中。

我们在Zipkin-Server中添加MySQL数据库驱动和JDBC依赖:

		<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-storage-mysql</artifactId>
            <version>${zipkin.version}</version>
        </dependency>

然后在application.yml中添加数据库连接信息:

spring:
  application:
    name: zipkin-server
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/zipkin?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8&useSSL=false
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
#指明使用mysql存储
zipkin:
  storage:
    type: mysql

配置文件中同时通过zipkin.storage.type=mysql指定了Zipkin的存储方式为MySQL。
接下来创建数据库和数据库表,新建一个名为zipkin的数据库,然后导入库表,库表SQL文件在io.zipkin.java:zipkin-storage-mysql依赖里可以找到。

Zipkin API
接口请求方式描述
/trace/{traceIdHex}GET根据Trace ID获取指定跟踪信息的Span列表
/tracesGET根据指定条件查询并返回符合条件的trace清单
/dependenciesGET用来获取通过收集到的Span分析出的依赖关系
/servicesGET用来获取服务列表
/spansGET根据服务名来获取所有的Span名
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值