Spring Cloud Sleuth(分布式服务跟踪)(1)

版权声明:版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37598011/article/details/82988215

首先准备工作如下:

1.服务注册中心:eureka-server。

2.微服务应用:trace-1,实现REST接口,并调用trace-2应用的接口。

其pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>trace-1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>trace-1</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.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-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>

应用主类如下:

@RestController
@EnableDiscoveryClient
@SpringBootApplication
public class Trace1Application {

    private final Logger logger=Logger.getLogger(getClass());

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

    @GetMapping("/trace-1")
    public String trace(){
        logger.info("---------------------------    trace1   ----------------------------------");
        return restTemplate().getForEntity("http://trace-2/trace-2",String.class).getBody();
    }

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

application.properties文件如下:

spring.application.name=trace-1
server.port=9101
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

3.创建第二个微服务应用:trace-2,实现REST接口/trace-2。

其pom.xml跟trace-1的pom文件相同。

应用主类如下:

@RestController
@EnableDiscoveryClient
@SpringBootApplication
public class Trace2Application {

    private final Logger logger=Logger.getLogger(getClass());

    @GetMapping("/trace-2")
    public String trace(){
        logger.info("---------------------------    trace2   ----------------------------------");
        return "Trace2";
    }

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

application.properties文件如下:

spring.application.name=trace-2
server.port=9102
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

启动三个服务后调用http://localhost:9101/trace-1

实现跟踪

首先在trace-1和trace-2的pom.xml文件中加入spring-cloud-starter-sleuth依赖:

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

然后访问http://localhost:9101/trace-1

第一个值:trace-1,它记录了应用的名称(application.properties中的spring.application.name参数配置的属性。)

第二个值:13a031b537091ddc,Spring Cloud Sleuth生成的一个ID,称为Trace ID,它用来标示一条请求链路。一条请求链路中包含一个Trace ID,多个Span ID。

第三个值:13a031b537091ddc,Spring Cloud Sleuth生成的另外一个ID,称为Span ID,他表示一个基本的工作单元,比如发送一个HTTP请求。

第四个值:false,表示是否要将该信息输出到Zipkin等服务中来收集和展示。

上面的Trace ID和Span ID是Spring Cloud Sleuth实现分布式服务跟踪的核心。在一次服务请求链路的调用中,会保持传递同一个Trace ID,从而将整个分布于不同微服务进程中的请求跟踪信息串联在一起。

跟踪原理

分布式系统中的服务跟踪在理论上实现不复杂,它主要有两个关键点:

1.为了实现请求跟踪,当请求发送到分布式系统的入口端点时,只需要服务跟踪框架为该请求创建一个唯一的跟踪标识,同时在分布式系统内部流转的时候,框架始终保持传递该唯一标识,直到返回给请求方为止,这个唯一标识就是前文中提到的 TraceID。通过 TraceID的记录,我们就能将所有请求过程日志关联起来。

2.为了统计各处理单元的时间延迟,当请求达到各个服务组件时,或是处理逻辑到达某个状态时,也通过一个唯一标识来标记它的开始、具体过程以及结束,该标识就是我们前文中提到的Span ID,对于每个Span来说,它必须有开始和结束两个节点,通过记录开始Span和结束Span的时间戳,就能统计出该Span的时间延迟,除了时间戳记录之外,它还可以包含一些其他元数据,比如:事件名称、请求信息等。

在Spring Boot应用中,通过在工程中引入spring-cloud-starter-sleuth依赖之后,它会自动为当前应用构建起各通信通道的跟踪机制,如:

1.通过RabbitMQ,Kafka传递请求

2.通过Zuul代理传递的请求

3.通过RestTemplate发起的请求

查看源码可以获取:

  • X-B3-TraceId:一条请求链路(Trace)的唯一标识,必须值

  • X-B3-SpanId:一个工作单元(Span)的唯一标识,必须值

  • X-B3-ParentSpanId::标识当前工作单元所属的上一个工作单元,Root Span(请求链路的第一个工作单元)的该值为空

  • X-B3-Sampled:是否被抽样输出的标志,1表示需要被输出,0表示不需要被输出

  • X-Span-Name:工作单元的名称

修改trace-2的实现:

@RestController
@EnableDiscoveryClient
@SpringBootApplication
public class Trace2Application {

    private final Logger logger = Logger.getLogger(getClass());

    @GetMapping("/trace-2")
    public String trace(HttpServletRequest request) {
        logger.info("---------------------------    trace2   ----------------------------------");
        logger.infof(" \n  TraceId={} \n  SpanId={} \n  ParentSpanId={} \n  Sampled={} \n  Name={}"
                , request.getHeader("X-B3-TraceId")
                , request.getHeader("X-B3-SpanId")
                , request.getHeader("X-B3-ParentSpanId")
                , request.getHeader("X-B3-Sampled")
                , request.getHeader("X-Span-Name"));
        return "Trace2";
    }

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

为了更直观的观察跟踪信息,可以在application.properties增加如下配置:

logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG

参考《Spring Cloud微服务实战》

猜你喜欢

转载自blog.csdn.net/qq_37598011/article/details/82988215