欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Cloud Sleuth介绍

程序员文章站 2022-06-12 15:21:02
...

背景

微服务架构下,一个请求可能会经过多个服务才会得到结果,如果在这个过程中出现了异常,就很难去定位问题。所以,必须要实现一个分布式链路跟踪的功能,直观的展示出完整的调用过程。

什么是Spring Cloud Sleuth?

Spring Cloud Sleuth是Spring Cloud提供的分布式系统服务链追踪组件,它大量借用了Google的Dapper,Twitter的Zipkin。学习Spring Cloud Sleuth,最好先对Zipkin有一些了解,对span、trace这些概念有相应的认识。

如何使用Spring Cloud Sleuth?

在这里,为了复习下之前学过的Spring Cloud相关的组件,会通过之前搭建的多个服务来学习。
microservice-provider:服务提供者
microservice-consumer:服务消费者
Eureka Server:作为注册中心,提供服务注册和服务发现的功能。
microservice-gateway:微服务网关,所有的调用,都是经过网关进行转发
microservice-zipkin-server:收集调用信息,提供界面进行查看

microservice-provider,microservice-consumer,microservice-gateway和microservice-zipkin-server都向Eureka Server注册;
microservice-consumer调用microservice-provider时,通过microservice-gateway进行调用。访问microservice-consumer时,通过microservice-gateway访问。
microservice-provider,microservice-consumer,microservice-gateway都向microservice-zipkin-server上报调用信息。

Eureka Server:

pom文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
</parent>

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

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置文件application.properties:

server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

Eureka Server启动端口为8761。

启动类:

@SpringBootApplication
@EnableEurekaServer//声明这是一个Eureka server
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

EurekaServerApplication上添加注解@EnableEurekaServer,声明这是一个Eureka server。

microservice-zipkin-server:
Zipkin需要配置jdk1.8才可以运行。
pom文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>io.zipkin.java</groupId>
        <artifactId>zipkin-server</artifactId>
    </dependency>
    <dependency>
        <groupId>io.zipkin.java</groupId>
        <artifactId>zipkin-autoconfigure-ui</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置文件application.yml:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 9411
spring:
  application:
    name: microservice-zipkin-server

启动类ZipkinServerApplication,添加@EnableZipkinServer注解,声明这是一个Zipkin Server,@EnableEurekaClient注解声明这是一个Eureka Client,向Eureka Server注册:

@SpringBootApplication
@EnableEurekaClient
@EnableZipkinServer
public class ZipkinServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipkinServerApplication.class, args);
    }
}

配置文件中,定义了服务的名称为microservice-zipkin-server,端口为9411,向地址为http://localhost:8761/eureka/ 的Eureka Server注册。

microservice-gateway:
网关服务的pom文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.SR5</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置文件application.properties:

server.port=9100
spring.application.name=microservice-gateway
spring.zipkin.base-url=http://localhost:9411
spring.sleuth.sampler.percentage=1.0
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

microservice-gateway配置了eureka.client.service-url.defaultZone向Eureka Server注册,配置了spring.zipkin.base-url,向Zipkin上报调用信息。配置spring.sleuth.sampler.percentage=1.0,说明采集率是100%,所有的数据都会上报给Zipkin,如果不配置,默认是10%。
上面的pom文件中,spring-cloud-starter-zipkin依赖了spring-cloud-starter-sleuth和spring-cloud-sleuth-zipkin,只需要在pom中添加spring-cloud-starter-zipkin,在配置文件中配置spring.zipkin.base-url,就可以为项目整合sleuth和zipkin。当有请求访问服务时,就会产生链路数据,自动向Zipkin上报。

启动类SpringCloudZuulApplication:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy // 声明这是一个zuul代理
public class SpringCloudZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudZuulApplication.class, args);
    }
}

microservice-provider
pom文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.3.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

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


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置文件application.properties:

server.port=8000
spring.application.name=microservice-provider
spring.zipkin.base-url=http://localhost:9411
spring.sleuth.sampler.percentage=1.0
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

启动类:

@EnableDiscoveryClient//声明是一个Eureka client
@SpringBootApplication
public class MicroServiceProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(MicroServiceProviderApplication.class, args);
    }
}

microservice-provider中还有一个ProviderController来提供服务,为了简单起见,直接返回hello world字符串。

@RestController
public class ProviderController {

    private final Logger logger = LoggerFactory.getLogger(ProviderController.class);

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping(value = "/provider", method = RequestMethod.GET)
    public String provider() {
        ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
        logger.info("host:{}, service_id:{}", serviceInstance.getHost(), serviceInstance.getServiceId());
        return "hello world";
    }
}

microservice-consumer
pom文件:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.3.RELEASE</version>
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.7</java.version>
</properties>

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


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Brixton.SR5</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

配置文件application.properties:

server.port=9000
spring.application.name=microservice-consumer
spring.zipkin.base-url=http://localhost:9411
spring.sleuth.sampler.percentage=1.0
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

启动类MicroServiceConsumeApplication:

@EnableDiscoveryClient
@SpringBootApplication
public class MicroServiceConsumeApplication {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

microservice-consumer在启动时,初始化RestTemplate实例,由于调用时是经过microservice-gateway的,microservice-gateway默认集成了Ribbon和Hystrix,所以RestTemplate不需要再用@LoadBalanced修饰。
microservice-consumer中有个ConsumerController,暴露接口,调用microservice-provider提供的服务。

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/consumer", method = RequestMethod.GET)
    public String consumer() {
        return this.restTemplate.getForEntity("http://localhost:9100/microservice-provider/provider", String.class).getBody();
    }
}

这些项目都创建好之后,启动,可以看到Eureka Server上,其它四个服务都注册上去了。
Spring Cloud Sleuth介绍

浏览器中输入http://localhost:9100/microservice-consumer/consumer,请求会经过microservice-gateway,转发到microservice-consumer的接口上,microservice-consumer再请求http://localhost:9100/microservice-provider/provider,还会经过microservice-gateway,转发到microservice-provider的接口上。最终会在页面上看到返回hello world。

Zipkin Server有提供的界面,可以直观的查看trace信息,浏览器输入http://localhost:9411,就可以看到刚才的调用已经生成了调用链,信息如下图所示。
Spring Cloud Sleuth介绍

点击一条详细记录,可以看到具体的调用信息:

Spring Cloud Sleuth介绍

从图中可以看出,这次调用涉及到三个服务,深度为5,包含5个span,右上角还有个Json按钮,可以查看json格式的数据。具体的含义可以学习Zipkin,就不再细说了。

参考资料:
1.《Spring Cloud与Docker微服务架构实战》 周立 著
2.《Spring Cloud微服务实战》 翟永超 著
3.《深入理解Spring Cloud与微服务构建》 方志朋 著