• springboot + dubbo 整合 zipkin 实现链路追踪



    springboot + dubbo 整合 zipkin 实现链路追踪

    示例说明

    本篇文章涉及三个微服务,分别为 dubbo-gateway,dubbo-alipay,dubbo-order,调用流程如下图所示:

    在这里插入图片描述

    zipkin 下载和启动

    zipkin 下载地址为 https://repo1.maven.org/maven2/io/zipkin/zipkin-server/,选择 zipkin-server-x.x.x-exec.jar 下载到本地。

    在 zipkin 下载目录下,打开命令行窗口,运行 java -jar java -jar zipkin-server-x.x.x-exec.jar 启动,启动成功后如下图:

    在这里插入图片描述

    浏览器输入 http://localhost:9411,如下图所示:

    在这里插入图片描述

    pom 文件配置

    向以上三个服务的 pom 文件中导入链路追踪需要的 jar 包

    		<!--链路追踪-->
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-bom</artifactId>
                <version>5.13.10</version>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-reporter-bom</artifactId>
                <version>2.16.3</version>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-instrumentation-dubbo</artifactId>
                <version>5.13.10</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-spring-beans</artifactId>
                <version>5.13.10</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-context-slf4j</artifactId>
                <version>5.13.10</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-sender-okhttp3</artifactId>
                <version>2.16.3</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-instrumentation-spring-webmvc</artifactId>
                <version>5.13.10</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-instrumentation-httpclient</artifactId>
                <version>5.13.10</version>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    yml 文件配置

    向以上三个服务的 yml 文件中增加如下配置:

    dubbo:
    	provider:
        	filter: tracing
    	consumer:
        	filter: tracing
    
    zipkin:
      enable: true
      base:
        url: http://127.0.0.1:9411/api/v2/spans # 注意,不可缺少 /api/v2/spans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    链路追踪配置类

    在以上三个微服务的 config 目录下创建链路追踪配置类,其内容如下:

    package com.stylefeng.guns.alipay.config;
    
    import brave.CurrentSpanCustomizer;
    import brave.SpanCustomizer;
    import brave.Tracing;
    import brave.context.slf4j.MDCScopeDecorator;
    import brave.http.HttpTracing;
    import brave.propagation.B3Propagation;
    import brave.propagation.ExtraFieldPropagation;
    import brave.propagation.ThreadLocalCurrentTraceContext;
    import brave.rpc.RpcTracing;
    import brave.sampler.Sampler;
    import brave.servlet.TracingFilter;
    import brave.spring.webmvc.SpanCustomizingAsyncHandlerInterceptor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import zipkin2.Span;
    import zipkin2.codec.Encoding;
    import zipkin2.reporter.AsyncReporter;
    import zipkin2.reporter.Sender;
    import zipkin2.reporter.okhttp3.OkHttpSender;
    
    import javax.servlet.Filter;
    
    /**
     * @ClassName TracingConfig
     * @Description TODO
     * @Author 听秋
     * @Date 2022/7/29 10:33
     * @Version 1.0
     **/
    @Configuration
    @Import(SpanCustomizingAsyncHandlerInterceptor.class)
    public class TracingConfig implements WebMvcConfigurer {
    
        @Bean
        Sender sender(@Value("${zipkin.base.url}") String url) {
            return OkHttpSender.newBuilder()
                    .encoding(Encoding.PROTO3)
                    .endpoint(url)
                    .build();
        }
    
        /**
         * Configuration for how to buffer spans into messages for Zipkin
         */
        @Bean
        @ConditionalOnBean(Sender.class)
        AsyncReporter<Span> spanReporter(Sender sender) {
            AsyncReporter.Builder builder = AsyncReporter.builder(sender);
            builder.queuedMaxSpans(50000);
            builder.queuedMaxBytes(104857600);
            return builder.build();
        }
    
    
        /**
         * Controls aspects of tracing such as the service name that shows up in the UI
         */
        @Bean
        Tracing tracing(@Value("${dubbo.application.name}") String applicationName, @Value("${zipkin.enable:false}") Boolean enable, @Autowired(required = false) AsyncReporter spanReporter) {
            Tracing.Builder builder = Tracing.newBuilder()
                    .localServiceName(applicationName)
                    .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "dubbo-alipay"))
                    .currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder()
                            // puts trace IDs into logs
                            .addScopeDecorator(MDCScopeDecorator.create())
                            .build()
                    );
            if (enable) {
                builder.spanReporter(spanReporter);
                builder.sampler(Sampler.ALWAYS_SAMPLE);
            } else {
                builder.sampler(Sampler.NEVER_SAMPLE);
            }
            return builder.build();
        }
    
        @Bean
        SpanCustomizer spanCustomizer(Tracing tracing) {
            return CurrentSpanCustomizer.create(tracing);
        }
    
        /**
         * Decides how to name and tag spans. By default they are named the same as the http method
         */
        @Bean
        HttpTracing httpTracing(Tracing tracing) {
            return HttpTracing.create(tracing);
        }
    
    
        @Bean
        RpcTracing rpcTracing(Tracing tracing) {
            return RpcTracing.create(tracing);
        }
    
        /**
         * Creates server spans for http requests
         */
        @Bean
        Filter tracingFilter(HttpTracing httpTracing) {
            return TracingFilter.create(httpTracing);
    
        }
    
        @Autowired
        SpanCustomizingAsyncHandlerInterceptor webMvcTracingCustomizer;
    
        /**
         * Decorates server spans with application-defined web tags
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(webMvcTracingCustomizer);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    日志文件配置

    在以上三个微服务的 resource 目录下创建 logback-spring.xml 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
    <!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
    <!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
    <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false-->
    <configuration scan="true" scanPeriod="10 seconds">
        <!--    <include resource="org/springframework/boot/logging/logback/base.xml"
                /> -->
        <contextName>Logback For Basic Platform</contextName>
        <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    
        <!-- 定义日志文件 输入位置 -->
        <springProperty scope="context" name="logDir" source="custom.log.dir" defaultValue="C:/logback/gateway"/>
    
        <!-- 定义日志文件 输出级别 -->
        <springProperty scope="context" name="logLevel" source="custom.log.level" defaultValue="info"/>
    
        <!-- 日志最大的历史 30-->
        <springProperty scope="context" name="logMaxHistory" source="custom.log.max-history" defaultValue="180"/>
    
        <!-- 控制台输出日志 -->
        <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%X{traceId},%X{spanId},%X{parentId}[%thread] %-5level %logger-%msg%n %ex{5}</pattern>
                <charset class="java.nio.charset.Charset">UTF-8</charset>
            </encoder>
        </appender>
    
    
        <!--文件日志, 按照每天生成日志文件 -->
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <fileNamePattern>${logDir}/%d{yyyy-MM-dd}/pf.%i.log.zip</fileNamePattern>
    
                <maxFileSize>50MB</maxFileSize>  <!-- 日志文件过大会使的编辑器打开非常慢,因此设置日志最大50MB -->
                <!--日志文件保留天数-->
                <maxHistory>${logMaxHistory}</maxHistory>
                <totalSizeCap>10GB</totalSizeCap>  <!-- 总日志大小 -->
            </rollingPolicy>
            <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}%X{traceId},%X{spanId},%X{parentId}[%thread] %-5level %logger-%msg%n %ex{5}</pattern>
            </encoder>
        </appender>
    
        <!-- 异步输出 -->
        <appender name="dayLogAsyncAppender" class="ch.qos.logback.classic.AsyncAppender">
            <includeCallerData>true</includeCallerData>
            <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
            <discardingThreshold>0</discardingThreshold>
            <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
            <queueSize>512</queueSize>
            <appender-ref ref="FILE"/>
        </appender>
    
    
        <!--专为 spring 定制
         -->
        <logger name="org.springframework" level="${logLevel}"/>
    
        <!-- root级别 DEBUG -->
        <root level="${logLevel}">
            <!-- 控制台输出 -->
            <appender-ref ref="STDOUT" />
            <!-- 文件输出 -->
            <appender-ref ref="dayLogAsyncAppender" />
        </root>
    </configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    验证

    编写接口和方法验证以上三个微服务的链路追踪情况(此处省略)。

    访问 http://localhost:9411/,将看到如下请求链路:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    CentOS 使用线程库Pthread 库
    【深度学习】图像分类数据集Fashion-MNIST
    企业级npm仓库搭建
    人生第一个java项目 学生管理系统
    AC笔记 | 领扣Java容器脚手架
    Java,回形数
    [跨数据库、微服务] FreeSql 分布式事务 TCC/Saga 编排重要性
    20231005使用ffmpeg旋转MP4视频
    ZMQ之异步管家模式
    增强现实基础介绍
  • 原文地址:https://blog.csdn.net/TQ20160412/article/details/126097421