微服务之链路追踪Zipkin

微服务之链路追踪

1.搭建Zipkin服务器

同时也作为Eureka的客户端注册到Eureka的服务中心。
引入依赖
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>spring.cloud</groupId>
    <artifactId>sleuth-zipkin</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>sleuth-zipkin</name>
    <description>sleuth-zipkin project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</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>
        <!-- sleuth -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!-- zipkin服务端包 -->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
            <version>2.12.3</version>
        </dependency>
        <!-- Zipkin用户配置包 -->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
            <version>2.12.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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>

application.yml

# 定义Spring应用名称,它是一个微服务的名称,一个微服务可拥有多个实例
spring:
  application:
    name: sleuth-zipkin

# 服务治理中心相互注册
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka,http://localhost:1002/eureka
management:
  metrics:
    web:
      server:
        # 取消自动定时,不设置为false可能时间序列数量增长过大,导致异常
        auto-time-requests: false

server:
  port: 5001

启动类 SleuthZipkinApplication.java

package com.spring.cloud.sleuth.zipkin.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin2.server.internal.EnableZipkinServer;

@SpringBootApplication
// 驱动Zipkin服务器
@EnableZipkinServer
public class SleuthZipkinApplication {

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

}

2.搭建Zipkin客户端

同时也是Eureka的客户端。
sleuth-provider (服务提供模块)
引入依赖

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>spring.cloud</groupId>
    <artifactId>sleuth-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>sleuth-provider</name>
    <description>sleuth-provider project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</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>
        <!-- sleuth -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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>

application.yml配置文件

# 定义Spring应用名称,他是一个微服务的名称,一个微服务可以拥有多个实例
spring:
  application:
    name: sleuth-provider
  sleuth:
    sampler: # 样本配置
      # 百分比,默认0.1
      probability: 1.0
      # 速率,每秒追踪30次
      # rate: 30
  zipkin:
    base-url: http://localhost:5001
# 注册到服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka,http://localhost:1002/eureka

server:
  port: 2001

启动类 SleuthProviderApplication.java

package com.spring.cloud.sleuth.provider.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages ="com.spring.cloud.sleuth.provider")
public class SleuthProviderApplication {

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

}

控制器 SleuthProviderController.java

package com.spring.cloud.sleuth.provider.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**** imports ****/
@RestController
public class SleuthProviderController {
    // 日志对象(org.slf4j.Logger)
    private static final Logger logger
            = LoggerFactory.getLogger(SleuthProviderController.class);

    // 提供的服务
    @GetMapping("/hello/{name}")
    public String sayHello(@PathVariable("name") String name)  {
        logger.info("请求参数:{}" , name);
        String helloResult = "hello " + name;
        logger.info("请求结果:{}", helloResult);
        return helloResult;
    }
}

sleuth-consumer (服务消费模块)
引入依赖
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>spring.cloud</groupId>
    <artifactId>sleuth-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>sleuth-consumer</name>
    <description>sleuth-consumer project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</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-openfeign</artifactId>
        </dependency>
        <!-- sleuth -->
        <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>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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>

application.yml配置文件

# 定义Spring应用名称,他是一个微服务的名称,一个微服务可以拥有多个实例
spring:
  application:
    name: sleuth-consumer
  sleuth:
    sampler: # 样本配置
      # 百分比,默认0.1
      probability: 1.0
      # 速率,每秒追踪30次
      # rate: 30
  zipkin:
    base-url: http://localhost:5001
# 注册到服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka,http://localhost:1002/eureka

server:
  port: 3001

启动类 SleuthConsumerApplication.java

package com.spring.cloud.sleuth.consumer.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**** imports ****/
@SpringBootApplication( // 定义扫描包
        scanBasePackages = "com.spring.cloud.sleuth.consumer")
@EnableFeignClients( //扫描装配OpenFeign接口到IoC容器中 ①
        basePackages="com.spring.cloud.sleuth.consumer")
public class SleuthConsumerApplication {


    @Bean
    @LoadBalanced // 负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

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

}

测试OpenFeign客户端,所以引入@FeignClient
SleuthFeign.java

package com.spring.cloud.sleuth.consumer.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// 声明为OpenFeign客户端
@FeignClient("sleuth-provider")
public interface SleuthFeign {

    @GetMapping("/hello/{name}")
    public String sayHello(@PathVariable("name") String name);
}

控制器 SleuthController.java

package com.spring.cloud.sleuth.consumer.controller;

import com.spring.cloud.sleuth.consumer.feign.SleuthFeign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**** imports ****/
@RestController
public class SleuthController {
    // 日志
    private static final Logger logger
            = LoggerFactory.getLogger(SleuthController.class);

    @Autowired
    private RestTemplate restTemplate = null;

    @Autowired
    private SleuthFeign sleuthFeign = null;

    // Ribbon的调用
    @GetMapping("/hello/rest/{name}")
    public String testResTemplate(@PathVariable("name") String name) {
        logger.info("使用RestTemplate,请求参数:{}", name );
        String url = "http://sleuth-provider/hello/{name}";
        logger.info("使用RestTemplate,请求URL:{}", url );
        String result = restTemplate.getForObject(url, String.class, name);
        logger.info("使用RestTemplate,请求结果:{}", result );
        return result;
    }

    // OpenFeign的调用
    @GetMapping("/hello/feign/{name}")
    public String testFeign(@PathVariable("name") String name) {
        logger.info("使用Open Feign,请求参数:{}", name );
        String result = sleuthFeign.sayHello(name);
        logger.info("使用Open Feign,请求结果:{}", result );
        return result;
    }
}

3.搭建Eureka服务治理中心

请参考Eureka篇。只需修改下端口号。

链路追踪需要从网关开始追踪,所以需要搭建网关,前面有搭建Getway的文章了,这里结束zuul网关的搭建

4.搭建网关

sleuth-zuul (微服务实例,同时也是Eureka的客户端和Zipkin客户端)
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>spring.cloud</groupId>
    <artifactId>sleuth-zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>sleuth-zuul</name>
    <description>sleuth-zuul project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- sleuth -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!-- 服务发现 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Zipkin客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!-- Zuul网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </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>

application.yml

# 定义Spring应用名称,他是一个微服务的名称,一个微服务可以拥有多个实例
spring:
  application:
    name: sleuth-zuul
  sleuth:
    sampler: # 样本配置
      # 百分比,默认0.1
      probability: 1.0
      # 速率,每秒追踪30次
      # rate: 30
  zipkin:
    base-url: http://localhost:5001

# 注册到服务治理中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1001/eureka,http://localhost:1002/eureka
# Zuul 路由配置
zuul:
  routes:
    provider:
      path: /provider/**
      service-id: sleuth-provider
    consumer:
      path: /consumer/**
      service-id: sleuth-consumer

server:
  port: 8001
  

启动类 SleuthZuulApplication.java

package com.spring.cloud.sleuth.zuul.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication(scanBasePackages="com.spring.cloud.sleuth.zuul")
@EnableZuulProxy // 驱动Zuul网关服务
public class SleuthZuulApplication {

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

}

自定义过滤器 TraceFilter.java

package com.spring.cloud.sleuth.zuul.filter;

import brave.Tracer;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

/**** imports ****/
@Component
public class TraceFilter extends ZuulFilter {

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

    // 注入Brave的Tracer对象
    @Autowired
    private Tracer tracer = null; // ①

    @Override
    public Object run() throws ZuulException {
        // 添加一个span的属性标记
        tracer.currentSpan().tag("1001", "GET请求");
        // 当前trace id
        String traceId = tracer.currentSpan().context().traceIdString();
        // 当前 span id
        String spanId = tracer.currentSpan().context().spanIdString();
        // 日志打印
        logger.info("当前追踪参数:traceId={},spanId={}", traceId, spanId);
        return null;
    }

    @Override
    public boolean shouldFilter() {
        // 获取请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        // 判断是否GET请求
        return "GET".equalsIgnoreCase(ctx.getRequest().getMethod());
    }

    // 过滤器顺序
    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER + 10;
    }

    // 过滤器类型为“pre”
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
}

启动各个微服务实例
浏览器访问http://localhost:8001/consumer/hello/feign/jim 和http://localhost:8001/consumer/hello/rest/jim
然后登录http://localhost:5001/zipkin/
就可以看到请求记录了。
同时sleuth-consumer的后台日志也可以看到请求日志。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芊芸爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值