dubbo服务链路跟踪方式

作者:燕少༒江湖 时间:2023-08-24 09:54:21 

目前很多业务使用微服务架构,服务模块划分有这2种方式:

  • 服务功能划分

  • 业务划分

不管哪种方式,一次接口调用都需要多个服务协同完成,其中一个服务出现问题,都会导致最终失败,虽然有logback + kafka + ELK 这样的神器架构,但是定位问题也很麻烦,如果在整个链路中,可以通过一个唯一ID(traceId)跟踪本次服务调用,就可以在ELK中查找当前traceId来定位问题。

一、案例

1、案例结构

dubbo服务链路跟踪方式

  • pratices-demo-provider-core:定义服务接口

  • pratices-demo-provider:具体实现

  • pratices-demo-consumer-core:服务消费者,同时也是服务提供者

  • pratices-demo-consumer:具体实现

  • pratices-demo-web:提供http服务

  • pratices-demo-trace:本案例的核心模块,在服务调用时拦截,设置traceId,跟踪本次服务调用

2、pratices-demo

2.1、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>
   <packaging>pom</packaging>
   <modules>
       <module>pratices-demo-consumer</module>
       <module>pratices-demo-provider</module>
       <module>pratices-demo-provider-core</module>
       <module>pratices-demo-consumer-core</module>
       <module>pratices-demo-web</module>
       <module>pratices-demo-trace</module>
   </modules>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.4.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.cn.dl</groupId>
   <artifactId>pratices-demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>pratices-demo</name>
   <description>Demo project for Spring Boot</description>

<properties>
       <java.version>1.8</java.version>
   </properties>

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

<dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-autoconfigure</artifactId>
       </dependency>
       <dependency>
           <groupId>com.alibaba</groupId>
           <artifactId>dubbo</artifactId>
           <version>2.6.0</version>
           <exclusions>
               <exclusion>
                   <groupId>org.springframework</groupId>
                   <artifactId>spring</artifactId>
               </exclusion>
               <exclusion>
                   <groupId>ch.qos.logback</groupId>
                   <artifactId>logback-core</artifactId>
               </exclusion>
               <exclusion>
                   <groupId>ch.qos.logback</groupId>
                   <artifactId>logback-access</artifactId>
               </exclusion>
               <exclusion>
                   <groupId>ch.qos.logback</groupId>
                   <artifactId>logback-classic</artifactId>
               </exclusion>
               <exclusion>
                   <groupId>org.slf4j</groupId>
                   <artifactId>slf4j-api</artifactId>
               </exclusion>
           </exclusions>
       </dependency>
       <dependency>
           <groupId>org.apache.zookeeper</groupId>
           <artifactId>zookeeper</artifactId>
           <version>3.4.10</version>
       </dependency>
       <!--Exception in thread "main" java.lang.NoClassDefFoundError: org/I0Itec/zkclient/IZkStateListener-->
       <!--Caused by: java.lang.ClassNotFoundException: org.I0Itec.zkclient.IZkStateListener-->
       <dependency>
           <groupId>com.101tec</groupId>
           <artifactId>zkclient</artifactId>
           <version>0.10</version>
           <exclusions>
               <exclusion>
                   <artifactId>slf4j-log4j12</artifactId>
                   <groupId>org.slf4j</groupId>
               </exclusion>
           </exclusions>
       </dependency>
   </dependencies>

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

<repositories>
       <repository>
           <id>spring-milestones</id>
           <name>Spring Milestones</name>
           <url>https://repo.spring.io/milestone</url>
       </repository>
       <repository>
           <id>spring-snapshots</id>
           <name>Spring Snapshots</name>
           <url>https://repo.spring.io/snapshot</url>
           <snapshots>
               <enabled>true</enabled>
           </snapshots>
       </repository>
   </repositories>
   <pluginRepositories>
       <pluginRepository>
           <id>spring-milestones</id>
           <name>Spring Milestones</name>
           <url>https://repo.spring.io/milestone</url>
       </pluginRepository>
       <pluginRepository>
           <id>spring-snapshots</id>
           <name>Spring Snapshots</name>
           <url>https://repo.spring.io/snapshot</url>
           <snapshots>
               <enabled>true</enabled>
           </snapshots>
       </pluginRepository>
   </pluginRepositories>

</project>

3、pratices-demo-provider-core

3.1、ProviderService


package com.cn.dl;

/**
* Created by yanshao on 2019-09-04.
*/
public interface ProviderService {
   String sayHello(String name);
}

4、pratices-demo-provider

dubbo服务链路跟踪方式

4.1、ProviderServiceImpl


package com.cn.dl.provider.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.cn.dl.ProviderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

/**
* Created by yanshao on 2019-09-04.
*/
@Service
public class ProviderServiceImpl implements ProviderService {

private static final Logger log = LoggerFactory.getLogger(ProviderServiceImpl.class);

@Override
   public String sayHello(String name) {
       log.info("providerServiceImpl 服务提供 traceId:{},sayHello:{}", MDC.get("traceId"),name);
       return "hello " + name ;
   }
}

4.2、dubbo-provider.properties 配置文件


# dubbo-provider.properties
dubbo.application.name=service2
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=50010
dubbo.consumer.timeout=5000

4.3、ProviderMain服务启动类

注意:启动dubbo服务不需要暴露http服务


package com.cn.dl;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.PropertySource;

import java.util.concurrent.locks.LockSupport;

/**
* Created by yanshao on 2019-09-04.
*/
@EnableDubbo(scanBasePackages = "com.cn.dl*")
@PropertySource("classpath:/dubbo-provider.properties")
@SpringBootApplication
public class ProviderMain{

private static final Logger log = LoggerFactory.getLogger(ProviderMain.class);
   /**
    * 启动dubbo服务,不需要提供web服务,但是默认有8080端口,通过一下方式可以不暴露web服务
    *
    * 1、在application.properties加上一下配置
    *
    * spring:
    *   main:
    *     allow-bean-definition-overriding: true
    *     web-application-type: none
    *
    * 2、修改启动类
    *  new SpringApplicationBuilder(ProviderMain .class)
    *                 .web(WebApplicationType.NONE)
    *                 .run(args)
    * */
   public static void main(String[] args)  {
       new SpringApplicationBuilder(ProviderMain.class).web(WebApplicationType.NONE).run(args);
       log.info("ProviderMain 启动了");
       LockSupport.park();
   }
}

@EnableDubbo(scanBasePackages = "com.cn.dl*")

扫描Dubbo的服务提供者以及Dubbo的服务消费者,一定要注意@EnableDubbo和@SpringBootApplication的先后次序;


@PropertySource("classpath:/dubbo-provider.properties")

加载配置文件到上下文环境变量。

5、pratices-demo-consumer-core

5.1、ConsumerService


package com.cn.dl;

/**
* Created by yanshao on 2019-09-04.
*/
public interface ConsumerService {
   String toSayHello(String name);
   int getRandomInt();
}

6、pratices-demo-consumer

dubbo服务链路跟踪方式

6.1、ConsumerServiceImpl


package com.cn.dl.consumer.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.cn.dl.ConsumerService;
import com.cn.dl.ProviderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.util.Random;

/**
* Created by yanshao on 2019-09-04.
*/
@Service
public class ConsumerServiceImpl implements ConsumerService {

private static final Logger log = LoggerFactory.getLogger(ConsumerServiceImpl.class);

@Reference
   private ProviderService providerService;

@Override
   public String toSayHello(String name) {
       String sayHello = providerService.sayHello(name);
       log.info("ConsumerServiceImpl >>>> traceId:{},sayHello:{}", MDC.get("traceId"),sayHello);
       return sayHello;
   }

@Override
   public int getRandomInt() {
       return new Random().nextInt(100);
   }
}

6.2、dubbo-consumer.properties


dubbo.application.name=service1
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.protocol.name=dubbo
dubbo.protocol.port=50020
dubbo.consumer.timeout=5000

6.3、ConsumerMain


package com.cn.dl;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.PropertySource;

import java.util.concurrent.locks.LockSupport;

/**
* Created by yanshao on 2019-09-04.
*/
@EnableDubbo(scanBasePackages = "com.cn.dl*")
@PropertySource("classpath:/dubbo-consumer.properties")
@SpringBootApplication
public class ConsumerMain {
   public static void main(String[] args) {
       new SpringApplicationBuilder(ConsumerMain.class).web(WebApplicationType.NONE).run(args);
       LockSupport.park();
   }
}

7、pratices-demo-web

7.1、WebTraceFilter

定义web * ,拦截所有请求,生成唯一ID


package com.cn.dl.webTrace;

import com.cn.dl.utils.TraceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.cn.dl.config.TraceConfig.TRACE_ID;

/**
* Created by yanshao on 2019-09-04.
*/
public class WebTraceFilter implements Filter {

private static final Logger log = LoggerFactory.getLogger(WebTraceFilter.class);

@Override
   public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       if (! (servletRequest instanceof HttpServletRequest) || ! (servletResponse instanceof HttpServletResponse)) {
           throw new ServletException("只支持http请求");
       }
       try {
           String traceId = TraceUtil.getTraceId();
           log.info("WebTraceFilter traceId:{}",traceId);
           MDC.put(TRACE_ID,traceId);
           filterChain.doFilter(servletRequest, servletResponse);
       } finally {
           MDC.remove(TRACE_ID);
       }
   }
}

7.2、TraceUtil


package com.cn.dl.utils;

import java.util.UUID;

/**
* Created by yanshao on 2019-09-04.
*/
public class TraceUtil {

public static String getTraceId(){
       return UUID.randomUUID().toString().replace("-","");
   }

public static void main(String[] args) {
       System.out.println(getTraceId());
   }
}

7.3、TraceConfig


package com.cn.dl.config;

/**
* Created by yanshao on 2019-09-04.
*/
public interface TraceConfig {
   String TRACE_ID = "traceId";
}

7.4、RpcProviderInterceptor


package com.cn.dl.rpcTrace;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.cn.dl.utils.TraceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;

import java.util.Map;

import static com.cn.dl.config.TraceConfig.TRACE_ID;
/**
* Created by yanshao on 2019-09-04.
*/
@Activate(group = Constants.PROVIDER)
public class RpcProviderInterceptor implements Filter {

private static final Logger log = LoggerFactory.getLogger(RpcProviderInterceptor.class);

@Override
   public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
       Result result;
       try {
           Map<String, String> at = invocation.getAttachments();
           MDC.put(TRACE_ID, ! StringUtils.isEmpty(at.get(TRACE_ID)) ? at.get(TRACE_ID): TraceUtil.getTraceId());
           result = invoker.invoke(invocation);
       } catch (Exception e) {
           log.error("RpcProviderInterceptor 异常",e);
           throw e;
       } finally {
           MDC.remove(TRACE_ID);
       }
       return result;
   }
}

7.5、RpcConsumerInterceptor


package com.cn.dl.rpcTrace;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.cn.dl.utils.TraceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.util.Map;

import static com.cn.dl.config.TraceConfig.TRACE_ID;
/**
* Created by yanshao on 2019-09-04.
*/
@Activate(group = Constants.CONSUMER)
public class RpcConsumerInterceptor implements Filter {

private static final Logger log = LoggerFactory.getLogger(RpcProviderInterceptor.class);

@Override
   public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
       Result result;
       try {
           Map<String, String> at = invocation.getAttachments();
           if (MDC.get(TRACE_ID) == null) {
               MDC.put(TRACE_ID,TraceUtil.getTraceId());
           }
           at.put(TRACE_ID, MDC.get(TRACE_ID));
           result = invoker.invoke(invocation);
       }catch (Exception e){
           log.error("RpcConsumerInterceptor 异常",e);
           throw e;
       }
       return result;
   }
}

7.6、RpcProviderInterceptor


package com.cn.dl.rpcTrace;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.cn.dl.utils.TraceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.util.StringUtils;

import java.util.Map;

import static com.cn.dl.config.TraceConfig.TRACE_ID;
/**
* Created by yanshao on 2019-09-04.
*/
@Activate(group = Constants.PROVIDER)
public class RpcProviderInterceptor implements Filter {

private static final Logger log = LoggerFactory.getLogger(RpcProviderInterceptor.class);

@Override
   public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
       Result result;
       try {
           Map<String, String> at = invocation.getAttachments();
           MDC.put(TRACE_ID, ! StringUtils.isEmpty(at.get(TRACE_ID)) ? at.get(TRACE_ID): TraceUtil.getTraceId());
           result = invoker.invoke(invocation);
       } catch (Exception e) {
           log.error("RpcProviderInterceptor 异常",e);
           throw e;
       } finally {
           MDC.remove(TRACE_ID);
       }
       return result;
   }
}

然后在resources下创建META-INF/dubbo/com.alibaba.dubbo.rpc.Filter,将扩展的 * 添加到dubbo调用链中


consumerTraceFilter=com.cn.dl.rpcTrace.RpcConsumerInterceptor
providerTraceFilter=com.cn.dl.rpcTrace.RpcProviderInterceptor

8、pratices-demo-web

dubbo服务链路跟踪方式

8.1、TraceInterceptor注册web *


package com.cn.dl.config;

import com.cn.dl.webTrace.WebTraceFilter;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;

import javax.annotation.Resource;
import javax.servlet.Filter;

/**
* Created by yanshao on 2019-09-04.
*/
@SpringBootConfiguration
public class TraceInterceptor {

@Bean(name = "webTraceFilter")
   public WebTraceFilter getWebTraceFilter(){
      return new WebTraceFilter();
   }

@Bean
   @Resource
   public FilterRegistrationBean traceFilterRegistration(Filter webTraceFilter) {
       FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
       registration.setFilter(webTraceFilter);
       registration.addUrlPatterns("/*");
       registration.setName("webTraceFilter");
       registration.setOrder(1);
       return registration;
   }
}

8.2、dubbo.properties


dubbo.application.name=consumer-service
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.consumer.timeout=5000

8.3、DemoWebController


package com.cn.dl.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.cn.dl.ConsumerService;
import org.springframework.web.bind.annotation.*;

/**
* Created by yanshao on 2019-09-04.
*/
@RestController
public class DemoWebController {

@Reference
   private ConsumerService consumerService;

@PostMapping("sayHello")
   public String sayHello(@RequestParam("name") String name){
       return consumerService.toSayHello(name);
   }

@GetMapping("getRandomInt")
   public int getRandomInt(){
       return consumerService.getRandomInt();
   }

}

8.4、StartWeb


package com.cn.dl;

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

/**
* Created by yanshao on 2019-09-04.
*/
@EnableDubbo(scanBasePackages = "com.cn.dl*")
@PropertySource("classpath:/dubbo.properties")
@SpringBootApplication
public class StartWeb {
   public static void main(String[] args) {
       SpringApplication.run(StartWeb.class,args);
   }
}

9、分别启动providerMain、consumerMain、startWeb

dubbo服务链路跟踪方式

dubbo服务链路跟踪方式

dubbo服务链路跟踪方式

dubbo服务链路跟踪方式

来源:https://blog.csdn.net/qq_31289187/article/details/100576585

标签:dubbo,服务,链路,跟踪
0
投稿

猜你喜欢

  • C#组合函数的使用详解

    2022-01-24 04:22:41
  • Android存储访问框架的使用小结

    2022-09-28 23:18:16
  • FFmpeg Principle分析Out put File 数据结构

    2023-02-17 08:26:49
  • Android实现淘宝客户端倒计时界面

    2023-09-18 21:25:09
  • android使用DataBinding来设置空状态

    2022-02-06 22:28:35
  • java中文转全拼工具类分享

    2022-02-07 09:50:57
  • Java实现发红包功能

    2023-12-09 10:33:03
  • Android下拉刷新官方版

    2021-11-25 06:52:51
  • C#编写的艺术字类实例代码

    2023-01-26 10:00:44
  • SpringBoot接口调用之后报404问题的解决方案

    2021-08-31 15:25:03
  • Unity使用鼠标旋转物体效果

    2021-10-17 05:08:12
  • Java实现驼峰、下划线互转的方法

    2023-08-18 09:17:54
  • 浅谈Spring中Bean的作用域、生命周期

    2023-11-14 02:44:21
  • c#防止多次运行代码收集分享

    2021-09-27 18:28:26
  • java操作solr实现查询功能的实例

    2023-08-04 10:41:34
  • Java import导入及访问控制权限修饰符原理解析

    2023-08-17 21:42:59
  • 使用Jitpack发布开源Java库的详细流程

    2021-12-18 06:55:58
  • android几种不同对话框的实现方式

    2022-09-13 06:31:42
  • 基于Ok+Rxjava+retrofit实现断点续传下载

    2021-08-27 02:21:49
  • Dubbo Consumer引用服务示例代码详解

    2022-04-26 03:56:44
  • asp之家 软件编程 m.aspxhome.com