SpringCloud Sleuth

简介

在这种大规模的分布式系统中,一个完整的系统是由多种不同的服务来共同支撑的,不同的系统可能分布在上千台服务器上,横跨多个数据中心,一旦系统出问题,此时问题的定位就比较麻烦。
分布式链路跟踪:
在微服务环境下,一次客户端请求,可能会引起数十次、上百次服务端服务之间的调用。一旦请求出问题了,我们需要考虑很多东西:

  • 如何快速定位问题?
  • 如果快速确定此次客户端调用,都涉及到哪些服务?
  • 到底是哪一个服务出问题了?
    要解决这些问题,就涉及到分布式链路追踪。
    分布式链路追踪系统主要用来跟踪服务调用记录的,一般来说,一个分布式链路追踪系统,有三个部分:
  • 数据收集
  • 数据存储
  • 数据展示
    Spring Cloud Sleuth(斯撸死)是SpringCloud提供的一套分布式链路跟踪系统
    trace:从请求到达系统开始,到给请求做出响应,这样一个过程成为 trace
    span:每次调用服务时,埋入的一个调用记录,成为 span
    annotation:相当于 span 的语法,描述 span 所处的状态。

简单应用

首先创建一个项目,引入Spring Cloud Sleuth

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

接下来创建一个HelloController,打印日志测试

@RestController
public class HelloController {
    RestTemplate restTemplate;

    public final static Logger logger = LoggerFactory.getLogger(HelloController.class);

    @GetMapping("/hello")
    public String hello(){
        logger.info("hello spring cloud sleuth");
        return "hello spring cloud sleuth";
    }
}

可以给当前服务配置一个名字,这个名字在输出的日志中会体现出来:

spring.application.name=javaboy-sleuth

启动应用,请求 /hello 接口,结果如下:

这个就是 Spring Cloud Sleuth 的输出。
再定义两个接口,在 hello2 中调用 hello3,形成调用链:

@SpringBootApplication
public class SpringCloudSleuthApplication {

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

@RestController
public class HelloController {
    @Autowired
    RestTemplate restTemplate;

    public final static Logger logger = LoggerFactory.getLogger(HelloController.class);

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

    @GetMapping("/hello3")
    public String hello3() throws InterruptedException {
        logger.info("hello3");
        Thread.sleep(500);
        return "hello3";
    }
}

此时,访问 hello2,会先调用 hello3,拿到返回结果,会给 hello2。

一个trace由多个span组成,一个trace相当于就是一个调用链,而一个span则是这个链中的每一次调用过程。
Spring Cloud Sleuth中也可以收集到异步任务中的信息
开启异步任务:


@SpringBootApplication
@EnableAsync
public class SpringCloudSleuthApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudSleuthApplication.class, args);
    }
    @Bean
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
/// 创建一个HelloService,提供一个异步任务方法;
public class HelloService {
    public final static Logger logger = LoggerFactory.getLogger(HelloController.class);

    @Async
    public String backgroundFun(){
        logger.info("backgroundFun");
        return "backgroundFun";
    }
}

再在HelloController中调用该异步方法:

  @GetMapping("/hello4")
  public String hello4(){
      logger.info("hello4");
      return helloService.backgroundFun();
  }

启动项目进行测试,发现Sleuth也打印出日志了,在异步方法中,异步任务是单独的spanid

Spring Cloud Sleuth 也可以手机定时任务的信息。
首先开启定时任务支持:

@SpringBootApplication
@EnableAsync
@EnableScheduling
public class SpringCloudSleuthApplication {

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

然后在HelloController,添加定时任务,去调用background方法

@Scheduled(cron = "0/10 * * * * ?")
public void sche1(){
    logger.info("start:");
    backgroundFun();
    logger.info("end:");
}

然后访问 hello4 接口进行测试。
在定时任务中,每一次定时任务都会产生一个新的 Trace,并且在调用过程中,SpanId 都是一致的,这个和普通的调用不一样。

posted @ 2020-08-17 16:05  柒丶月  阅读(473)  评论(0编辑  收藏  举报