Dubbo如何传递链路追踪id?
1.什么是链路追踪?
分布式链路追踪就是将一次分布式请求还原成调用链路,将一次分布式请求的调用情况集中展示,比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。
链路跟踪主要功能:
- 故障快速定位:可以通过调用链结合业务日志快速定位错误信息。
- 链路性能可视化:各个阶段链路耗时、服务依赖关系可以通过可视化界面展现出来。
- 链路分析:通过分析链路耗时、服务依赖关系可以得到用户的行为路径,汇总分析应用在很多业务场景。
应用场景
在现行微服务的趋势下,一次调用的过程中涉及多个服务节点,产生的日志分布在不同的服务器上,如果需要查看一次调用的全链路日志,则一般的做法是通过在系统边界中产生一个 traceId,向调用链的后续服务传递 traceId,后续服务继续使用 traceId 打印日志,并再向其他后续服务传递 traceId,此过程简称,traceId透传。 在使用HTTP协议作为服务协议的系统里,可以统一使用一个封装好的http client做traceId透传。但是dubbo实现traceId透传就稍微复杂些了。一般情况下,会自定义Filter来实现traceId透传。
探寻原理
链路追踪系统(可能)最早是由Goggle公开发布的一篇论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》被大家广泛熟悉,大家感兴趣的话可以去看一看
2.代码工程
前提条件:dubbo工程如何搭建详:Spring Boot集成dubbo快速入门Demo
实验目标
实现消费者和生产者之间传递traceID
消费者
配置过滤器
package com.et.consumer.config;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@Slf4j
@Activate(group = {Constants.CONSUMER})
public class ConsumerFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Object token = MDC.get("TRACKING_LOG_SESSION_TOKEN_ID");
if (token != null) {
log.info("----cunsumer trace id:{}",token);
RpcContext.getContext().setAttachment("TRACKING_LOG_SESSION_TOKEN_ID", token.toString());
}
Result result = invoker.invoke(invocation);
return result;
}
}
在dubbo-samples-spring-boot-consume/src/main/resources/META-INF/dubbo下面配置过滤器
ConsumerFilter=com.et.consumer.config.ConsumerFilter
生产者
配置过滤器
package com.et.provider.config;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
@Slf4j
@Activate(group = { Constants.PROVIDER })
public class ProviderFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
String var = RpcContext.getContext().getAttachment("TRACKING_LOG_SESSION_TOKEN_ID");
MDC.put("TRACKING_LOG_SESSION_TOKEN_ID", var);
log.info("----->provider trance id:{}",var);
Result result = invoker.invoke(invocation);
MDC.remove("TRACKING_LOG_SESSION_TOKEN_ID");
return result;
}
}
在dubbo-samples-spring-boot-provider/src/main/resources/META-INF/dubbo下面配置过滤器
ProviderFilter=com.et.provider.config.ProviderFilter
以上只是一些关键代码,所有代码请参见下面代码仓库
代码仓库
- https://github.com/Harries/springboot-demo(dubbo)
3.测试
- 启动dubbo-samples-spring-boot-provider
- 启动dubbo-samples-spring-boot-consume
- 访问http://127.0.0.1:8080/user/info
消费端日志
2024-08-29 23:46:24.497 [1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9] [http-nio-8080-exec-1] INFO c.et.consumer.config.ConsumerFilter [ConsumerFilter.java:16] - ----cunsumer trace id:1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9
服务端日志
2024-08-29 23:46:24.589 [1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9] [DubboServerHandler-192.168.0.100:20880-thread-2] INFO c.et.provider.config.ProviderFilter [ProviderFilter.java:18] - ----->provider trance id:1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9
2024-08-29 23:46:24.595 [1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9] [DubboServerHandler-192.168.0.100:20880-thread-2] INFO c.e.provider.service.UserServiceImpl [UserServiceImpl.java:19] - this is a test
实验结果表明traceid【1AB90DBB-06CA-4D35-8A2E-BEDBB4F86DA9】在消费者和服务者之间传递
4.总结
dubbo通过spi和Adaptive注解来实现链路追踪id传递
dubbo的SPI
dubbo在原有的spi基础上主要有以下的改变,①配置文件采用键值对配置的方式,使用起来更加灵活和简单 ② 增强了原本SPI的功能,使得SPI具备ioc和aop的功能,这在原本的java中spi是不支持的。dubbo的spi是通过ExtensionLoader来解析的,通过ExtensionLoader来加载指定的实现类,配置文件的路径在META-INF/dubbo路径下
@Adaptive注解的作用是什么?
Dubbo通过注解@Adaptive作为标记实现了一个适配器类,dubbo将会为这个类动态生成代理对象;ExtensionLoader中获取默认实现类或者通过实现类名称(由@SPI注解指定的名称)来获取实现类 为什么会出现@Adaptive这个注解呢?主要原因是因为dubbo的加载扩展了是从配置文件加载的,是很动态的,但是实现类却要固定写死或者灵活实现,所以就得区分开。用@Adaptive就是表示由框架自己生成,不需要人为实现.在dubbo加载SPI时会动态创建SPI Adaptive实现ExtensionLoader。
- ExtensionLoader 类里声明了以下几个文件夹都可以使用
private static final String SERVICES_DIRECTORY = "META-INF/services/"; private static final String DUBBO_DIRECTORY = "META-INF/dubbo/"; private static final String DUBBO_INTERNAL_DIRECTORY = "META-INF/dubbo/internal/";
5.引用
- Peter Bourgon · Metrics, tracing, and logging
- Dubbo如何传递链路追踪id? | Harries Blog™
- https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/service/attachment/