原创

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
consumer

生产者

配置过滤器
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
    provider

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.引用

   
正文到此结束
Loading...