Spring Cloud框架学习-Spring Cloud Sleuth

1. 简介

在微服务架构的系统中,一次客户端请求,可能会引起数十次、上百次服务端服务之间的调用。一旦请求出问题了,我们需要考虑很多东西:

  • 如何快速定位问题?
  • 如果快速确定此次客户端请求都涉及到哪些服务?
  • 到底是哪一个服务出问题了?

要解决这些问题,就涉及到分布式链路追踪。分布式链路追踪系统主要用来跟踪服务调用记录的,一般来说,一个分布式链路追踪系统,有三个部分:数据收集、数据存储、数据展示。

Spring Cloud Sleuth 是 Spring Cloud 提供的一套分布式链路追踪系统。它可以直观地展示出一次请求的调用过程。

  • trace:从请求到达系统开始,到给请求做出响应,这样一个过程成为 trace
  • span:每次调用服务时,埋入的一个调用记录,成为 span
  • annotation:相当于 span 的语法,描述 span 所处的状态

2. 基本应用

创建Maven项目,引入如下依赖:


<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">
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.3.1.RELEASEversion>
        <relativePath/> 
    parent>
    <modelVersion>4.0.0modelVersion>

    <groupId>top.javahaigroupId>
    <artifactId>sleuthartifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-sleuthartifactId>
            <version>2.2.8.RELEASEversion>
        dependency>
    dependencies>

project>

创建HelloController,测试日志打印:

@RestController
public class HelloController {

    private static final Log log = LogFactory.getLog(HelloController.class);
    @GetMapping("/hello")
    public String hello() {
        log.info("hello spring cloud sleuth");
        return "hello spring cloud sleuth";
    }
}

启动应用,浏览器请求/hello接口控制台输出:
在这里插入图片描述

定义hello2和hello3接口,实现hello2调用hello3接口,形成调用链。

@RestController
public class HelloController {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    HelloService helloService;

    private static final Log log = LogFactory.getLog(HelloController.class);
    @GetMapping("/hello")
    public String hello() {
        log.info("hello spring cloud sleuth");
        return "hello spring cloud sleuth";
    }

    @GetMapping("/hello2")
    public String hello2() throws InterruptedException {
        log.info("hello2");
        Thread.sleep(500);
        return restTemplate.getForObject("http://localhost:8080/hello3",
                String.class);
    }
    @GetMapping("/hello3")
    public String hello3() throws InterruptedException {
        log.info("hello3");
        Thread.sleep(500);
        return "hello 3";
    }

}

控制台输出如下
在这里插入图片描述
一个 trace 由多个 span 组成,一个trace 相当于就是一个调用链,而一个 span 则是这个链中的每一次
调用过程。

Spring Cloud Sleuth 中也可以收集到异步任务和定时任务中的信息。
开启异步任务和定时任务:

@SpringBootApplication
//开启异步任务
@EnableAsync
//开启定时任务
@EnableScheduling
public class SleuthApplication {

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


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

创建HelloService类,提供异步任务和定时任务方法:

@Service
public class HelloService {

    private static final Log log = LogFactory.getLog(HelloService.class);

    /**
     * 异步任务
     * @return
     */
    @Async
    public String asyncFun() {
        log.info("asyncFun");
        return "asyncFun";
    }

    /**
     * 定时任务,每10秒调用一次
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void scheduleTask() {
        log.info("scheduleTask start");
        asyncFun();
        log.info("scheduleTask end");

    }
}

在HelloController方法中定义hello4接口,调用异步方法helloService.asyncFun:

    @GetMapping("/hello4")
    public String hello4() throws InterruptedException {
        log.info("hello4");
        return helloService.asyncFun();
    }

重启项目,调用/hello4接口,查看控制台输出日志。可以看到在异步任务中,异步任务是单独的 spanid。
在这里插入图片描述
而次定时任务都会产生一个新的 TraceId,并且在调用过程中,SpanId 都是一致的,这
个和普通的调用不一样。
在这里插入图片描述

3. 整合Zipkin

Zipkin是Twitter的一个开源项目,可以用来获取和分析Spring Cloud Sleuth 中产生的请求链路跟踪日志,它提供了Web界面来帮助我们直观地查看请求链路跟踪信息。

3.1 Zipkin安装

3.1.1 安装Elasticsearch

安装Zipkin前首先需要 安装Elasticsearch,使用Elasticsearch作为数据存储工具,用于存储服务链路的跟踪信息。下面都使用Docker方式进行安装。

es 安装命令:

docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms128m -Xmx512m" elasticsearch:7.1.0

浏览器访问服务器的9200端口返回如下信息则说明ES服务器已成功启动。
Spring Cloud框架学习-Spring Cloud Sleuth_第1张图片

3.1.2 安装Elasticsearch-head

接下来Elasticsearch可视化工具es-head ,方便查看数据,可视化工具 es-head 有三种安装方式:

  1. 直接下载软件安装
  2. 通过 Docker 安装
  3. 安装 Chrome/Firefox 插件

拉取elasticsearch-head镜像

docker pull mobz/elasticsearch-head:5

运行镜像

docker run -d -p 9100:9100 mobz/elasticsearch-head:5

进入elasticsearch容器中

docker exec -it 160327b0a4fa /bin/bash

打开config目录下elasticsearch.yml配置文件

在这里插入图片描述
镜像一般不会配置有vim,CentOS的软件安装工具是yum,我们使用yum先下载vim

yum install -y vim

elasticsearch.yml配置文件中添加跨域配置

http.cors.enabled: true
http.cors.allow-origin: '*'

重启elasticsearch容器

docker restart 160327b0a4fa

浏览器访问,如果集群健康显示green则说明成功连接了elasticsearch
Spring Cloud框架学习-Spring Cloud Sleuth_第2张图片

3.1.3 安装RabbitMQ

https://blog.csdn.net/aiwangtingyun/article/details/123616

3.1.4 安装Zipkin

直接运行如下命令安装Zipkin

docker run -d -p 9411:9411 --name zipkin -e ES_HOSTS=10.0.16.9 -e STORAGE_TYPE=elasticsearch -e ES_HTTP_LOGGING=BASIC -e RABBIT_URI=amqp://guest:[email protected]:5672 openzipkin/zipkin 

Spring Cloud框架学习-Spring Cloud Sleuth_第3张图片

3.2 测试使用

创建Maven项目,添加如下依赖:


<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">
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.6.3version>
        <relativePath/> 
    parent>
    <modelVersion>4.0.0modelVersion>

    <groupId>top.javahaigroupId>
    <artifactId>zipkinartifactId>


    <properties>
        <java.version>1.8java.version>
        <spring-cloud.version>2021.0.0spring-cloud.version>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-sleuthartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-streamartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-stream-binder-rabbitartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-sleuth-zipkinartifactId>
        dependency>

    dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring-cloud.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>
project>

application.properties添加如下配置:

#服务名
spring.application.name=zipkin01

spring.sleuth.web.client.enabled=true
# 配置采样比例,默认为 0.1
spring.sleuth.sampler.probability=1
# zipkin 地址
spring.zipkin.base-url=http://101.43.30.7:9411
# 开启 zipkin
spring.zipkin.enabled=true
# 追踪消息的发送类型
spring.zipkin.sender.type=rabbit
spring.rabbitmq.host=101.43.30.7
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

启动类配置:

@SpringBootApplication
public class ZipkinApplication {

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


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

创建HelloController类,提供接口/hello

@RestController
public class HelloController {

    private static final Logger logger =
            LoggerFactory.getLogger(HelloController.class);
    @GetMapping("/hello")
    public String hello(String name) {
        logger.info("zipkin01-hello");
        return "hello " + name + " !";
    }
}

复制上面创建的项目,新建一个zipkin02项目,修改配置文件

#服务名
server.port=8082
spring.application.name=zipkin02

spring.sleuth.web.client.enabled=true
# 配置采样比例,默认为 0.1
spring.sleuth.sampler.probability=1
# zipkin 地址
spring.zipkin.base-url=http://101.43.30.7:9411
# 开启 zipkin
spring.zipkin.enabled=true
# 追踪消息的发送类型
spring.zipkin.sender.type=rabbit
spring.rabbitmq.host=101.43.30.7
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

同样创建HelloController类,提供接口/hello,调用zipkin01的hello接口

@RestController
public class HelloController {

    @Autowired
    RestTemplate restTemplate;


    private static final Logger logger =
            LoggerFactory.getLogger(HelloController.class);
    @GetMapping("/hello")
    public String hello() {
        logger.info("zipkin02-hello");
        String s = restTemplate.getForObject("http://localhost:8080/hello?name={1}",String.class, "hello world");
        logger.info(s);
        return s;
    }
}

启动两个项目,浏览器访问zipkin02的hello接口

Spring Cloud框架学习-Spring Cloud Sleuth_第4张图片
打开zipkin查看这条链路调用,我们可以通过zipkin直观地看到请求调用链路和通过每个服务的耗时等信息。
Spring Cloud框架学习-Spring Cloud Sleuth_第5张图片

你可能感兴趣的:(Spring,Cloud,spring,cloud,学习,java)