dubbo服务链路跟踪方式
作者:燕少༒江湖 时间:2023-08-24 09:54:21
目前很多业务使用微服务架构,服务模块划分有这2种方式:
服务功能划分
业务划分
不管哪种方式,一次接口调用都需要多个服务协同完成,其中一个服务出现问题,都会导致最终失败,虽然有logback + kafka + ELK 这样的神器架构,但是定位问题也很麻烦,如果在整个链路中,可以通过一个唯一ID(traceId)跟踪本次服务调用,就可以在ELK中查找当前traceId来定位问题。
一、案例
1、案例结构
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
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
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
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
来源:https://blog.csdn.net/qq_31289187/article/details/100576585
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
C#组合函数的使用详解
Android存储访问框架的使用小结
![](https://img.aspxhome.com/file/2023/7/110757_0s.png)
FFmpeg Principle分析Out put File 数据结构
![](https://img.aspxhome.com/file/2023/5/139155_0s.jpg)
Android实现淘宝客户端倒计时界面
![](https://img.aspxhome.com/file/2023/9/93309_0s.gif)
android使用DataBinding来设置空状态
![](https://img.aspxhome.com/file/2023/4/88344_0s.gif)
java中文转全拼工具类分享
Java实现发红包功能
Android下拉刷新官方版
![](https://img.aspxhome.com/file/2023/6/139556_0s.gif)
C#编写的艺术字类实例代码
SpringBoot接口调用之后报404问题的解决方案
![](https://img.aspxhome.com/file/2023/4/86834_0s.png)
Unity使用鼠标旋转物体效果
![](https://img.aspxhome.com/file/2023/6/68616_0s.png)
Java实现驼峰、下划线互转的方法
浅谈Spring中Bean的作用域、生命周期
![](https://img.aspxhome.com/file/2023/7/59567_0s.png)
c#防止多次运行代码收集分享
java操作solr实现查询功能的实例
![](https://img.aspxhome.com/file/2023/0/95940_0s.png)
Java import导入及访问控制权限修饰符原理解析
使用Jitpack发布开源Java库的详细流程
![](https://img.aspxhome.com/file/2023/5/63395_0s.png)
android几种不同对话框的实现方式
![](https://img.aspxhome.com/file/2023/3/98693_0s.png)
基于Ok+Rxjava+retrofit实现断点续传下载
![](https://img.aspxhome.com/file/2023/5/108435_0s.jpg)