【Dubbo】Dubbo简单自定义链路传递traceId

需求

因为服务器内存不足,没有引入链路追踪的框架,项目使用到了Dubbo,所有通过self4j的MDC和Dubbo的RpcContext实现简单的traceId 的多服务模块的传递

解决思路

  1. 在第一个模块生成traceId(比如网关模块),生成traceId,并存入MDC,RpcContext,请求头等地方,使用完在响应时进行删除
  2. 如果是Dubbo的Rpc调用则能将traceId传递到服务提供者模块,服务端通过过滤器进行拦截,加入到自己的MDC,RpcContext,使用完后清除
  3. 如果是网关的转发请求,则通过请求头进行转发traceId,下游模块存入自己的MDC,RpcContext,使用完后清除
  4. 因为Dubbo的RpcContext每次调用服务端方法后,消费端的RpcContext就会被清除,所有通过MDC在每次rpc调用前通过调用前过滤器再加上traceId

版本

java 复制代码
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>3.1.6</version>
        </dependency>

解决方案

Dubbo消费端过滤器

就是调用服务器提供者的接口前,在消费端先过滤,加一点参数啥的,再转发

以下默认已经配置好,并写好了Dubbo远程调用服务,并能够进行调用。在此基础上进行过滤器添加。

1 . 代码

java 复制代码
@Activate(group = {CommonConstants.CONSUMER}, order = -30000)
@Slf4j
public class RemoteTraceIdFilter implements Filter {
    private static final String TRACE_ID = "traceId";

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 消费者
        RpcServiceContext currentServiceContext = RpcContext.getCurrentServiceContext();
        boolean consumerSide = currentServiceContext.isConsumerSide();
        if (consumerSide) {
            String traceId = MDC.get(TRACE_ID);
            if(traceId==null){
                traceId = UUID.randomUUID().toString();
            }
            //消费者 将trace_id(业务流水号) set至上下文中
            RpcContext.getClientAttachment().setAttachment(TRACE_ID, traceId);
        } else {
            // 服务提供者
//            String traceId = RpcContext.getClientAttachment().getAttachment(TRACE_ID);
            String traceId = RpcContext.getServerAttachment().getAttachment(TRACE_ID);
            if (traceId == null) {
                traceId = UUID.randomUUID().toString();
            }
            //slf4j 中设置了日志打印格式用作日志链路追踪
            MDC.put(TRACE_ID, traceId);
        }
        try {
            return invoker.invoke(invocation);
        } finally {
            if (RpcContext.getCurrentServiceContext().isProviderSide()) {
                MDC.remove(TRACE_ID);
            }else{
                RpcContext.getClientAttachment().removeAttachment(TRACE_ID);
            }
        }
    }
}
  1. 配置
    1. 创建Resource相关配置(可以参考官方文档 官网)

    --META-INF
    ----dubbo
    ------org.apache.dubbo.rpc.Filter

    文件内容(traceId是自定义的,具体看官网)
    traceId = 类路径

Dubbo服务提供端过滤器

一个样不赘述

问题

  1. 每次RpcContext中存入值,在过滤器finally都要删除防止内存泄漏
  2. 每次RpcContext中存入值,并调用一次接口后,在消费端再次获取时会获取不到,因为已经被自动删除了,所有此处用了MDC配合RpcContext实现了traceId的保留。
    具体看官网: 链路传递
  3. 侵入性比较高,实现也比较粗糙,如果条件允许建议直接使用sentinel等专业高级好用的框架直接实现链路的追踪

总结

此方式只是一个简单的实现,真实场景允许条件下直接使用sentinel等专门框架完成的限流链路追踪的功能。

相关推荐
TracyCoder1237 小时前
Dubbo+Zookeeper怎么实现的服务注册与发现
分布式·zookeeper·dubbo
编啊编程啊程3 天前
【044】Dubbo3从0到1系列之ExecutorRepository接口详解
rpc·dubbo
拾忆,想起4 天前
Dubbo跨机房调用实战:从原理到架构的完美解决方案
服务器·网络·网络协议·tcp/ip·架构·dubbo
拾忆,想起4 天前
Dubbo网络延迟全链路排查指南:从微服务“快递”到光速传输
网络·网络协议·微服务·架构·php·dubbo
托尼吴5 天前
REST RPC dubbo,HSF 协议总结
网络协议·rpc·dubbo
拾忆,想起6 天前
Dubbo超时问题排查与调优指南:从根因到解决方案
服务器·开发语言·网络·微服务·架构·php·dubbo
白露与泡影6 天前
2025年BAT面试题汇总:JVM+Spring+Dubbo+Redis+并发编程
jvm·spring·dubbo
拾忆,想起7 天前
Dubbo服务上线无法调用?一站式排查指南来了
服务器·网络·网络协议·tcp/ip·dubbo
拾忆,想起8 天前
Dubbo核心架构全解析:构建微服务通信的高速公路
java·微服务·云原生·架构·dubbo·哈希算法
扬道财经9 天前
从百度分析师到GEO理论奠基人,罗小军探索AI搜索营销新路径
人工智能·百度·dubbo