基于「ZipKin」实现Springboot+Dubbo微服务应用的链路追踪

944 阅读2分钟

前言

基于微服务架构构建的应用,如果不能看到一个接口从前端发起到后端各个应用的调用链路,在排查问题,应用监控方面都会比较困难,所以实现微服务的调用链路追踪时非常有必要的。

本文基于SpringCloudSleuth + SpringCloudZipKin来实现微服务的调用链路追踪。

主要jar包版本

  • Dubbo 2.6.10.1
  • Springboot 2.3.12.RELEASE
  • SpringCloudZipKin 2.2.8.RELEASE
  • SpringCloudSleuth 2.2.8.RELEASE

搭建zipkin本地环境

下载并启动

curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

访问

浏览器访问如下路径就可以看到zipkin的web界面了。

localhost:9411/zipkin

image-20230315151931841.png

搭建微服务应用

基于SpringBoot + Dubbo构建一个简单的微服务体系。包括一个dubbo provider应用,dubbo consumer应用。

整体目录结构

image-20230315153018437.png

父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>
​
    <groupId>com.example</groupId>
    <artifactId>springboot-dubbo-zipkin-sleuth-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>springboot-dubbo-zipkin-sleuth-example</name>
    <description>springboot-dubbo-zipkin-sleuth-example</description>
​
    <modules>
        <module>dubbo-provider</module>
        <module>dubbo-consumer</module>
        <module>dubbo-api</module>
    </modules>
​
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/>
    </parent>
​
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.10.1</version>
            <scope>provided</scope>
        </dependency>
​
        <dependency>
            <groupId>org.jboss.netty</groupId>
            <artifactId>netty</artifactId>
            <version>3.2.10.Final</version>
        </dependency>
​
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>log4j</groupId>
                    <artifactId>log4j</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
​
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
            <version>5.1.0</version>
        </dependency>
​
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>5.1.0</version>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
            <version>2.2.8.RELEASE</version>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
            <version>2.2.8.RELEASE</version>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
​
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
​
        <dependency>
            <groupId>io.zipkin.brave</groupId>
            <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
            <version>5.13.3</version>
        </dependency>
​
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
​
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

创建dubbo-api

定义测试接口

public interface DemoService {
    String sayHello(String name);
}

创建dubbo 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>springboot-dubbo-zipkin-sleuth-example</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
​
    <artifactId>dubbo-provider</artifactId>
​
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
​
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
  • 启动类
@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}
  • 接口实现
@Service
@Slf4j
public class DemoServiceImpl implements DemoService {
    @Override
    public String sayHello(String name) {
        return "Hello" + name;
    }
}
  • application.properties
server.port=8100
spring.application.name=dubbo-provider
spring.sleuth.sampler.rate=100
spring.zipkin.base-url=http://127.0.0.1:9411/
spring.zipkin.enabled=truedubbo.application.name=provider
dubbo.application.id=provider
dubbo.application.version=1.0.0
dubbo.application.qos.port=2224
dubbo.protocol.server=netty
dubbo.protocol.name=dubbo
dubbo.protocol.port=20882
dubbo.protocol.threadpool=fixed
dubbo.protocol.threads=500
dubbo.protocol.queues=1000
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.provider.timeout=5000
dubbo.provider.retries=1
dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false
# 重要配置
dubbo.consumer.filter=tracing
dubbo.provider.filter=tracing

# 重要配置
logging.level.root=info
logging.pattern.console=[%p][%t][%d{yyyy-MM-dd HH:mm:ss.SSS}][%c][%L][%X{traceId}][%X{spanId}]%m%n

创建dubbo 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.example</groupId>
        <artifactId>springboot-dubbo-zipkin-sleuth-example</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
​
    <artifactId>dubbo-consumer</artifactId>
    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>dubbo-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies></project>
  • application.properties
server.port=8101
spring.application.name=dubbo-consumer
spring.sleuth.sampler.rate=100
spring.zipkin.base-url=http://127.0.0.1:9411/
spring.zipkin.enabled=truedubbo.application.name=consumer
dubbo.application.id=consumer
dubbo.application.version=1.0.0
dubbo.application.qos.port=2223
dubbo.protocol.server=netty
dubbo.protocol.name=dubbo
dubbo.protocol.port=20886
dubbo.protocol.threadpool=fixed
dubbo.protocol.threads=500
dubbo.protocol.queues=1000
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.provider.timeout=5000
dubbo.provider.retries=1
dubbo.reference.check=false
dubbo.consumer.check=false
dubbo.registry.check=false
# 重要配置
dubbo.consumer.filter=tracing
dubbo.provider.filter=tracing

# 重要配置
logging.level.root=info
logging.pattern.console=[%p][%t][%d{yyyy-MM-dd HH:mm:ss.SSS}][%c][%L][%X{traceId}][%X{spanId}]%m%n
  • 测试controller
@RestController
@RequestMapping
@Slf4j
public class HelloController {
    @Reference(retries = 0)
    DemoService demoService;
​
    @GetMapping("/helloDubbo")
    public String helloDubbo() {
        return demoService.sayHello("haha");
    }
}

验证

终端访问接口:

curl http://localhost:8101/helloDubbo

可以看到调用信息,点击show后可以看到详细的调用链路,这样一个简单链路追踪功能就搭建好了。

image-20230315154600394.png

image-20230315154623369.png

总结

zipkin默认将数据保存内存中,重启zipkin后数据就会丢失,在正式环境肯定是不合适的,官方提供了多种数据存储方式,包括mysql、es等,可根据具体需要参照官方文档实现。

参考资料

zipkin.io/pages/quick…

docs.spring.io/spring-clou…