图文并茂分析Skywalking dubbo上下午传递源码

这里是weihubeats ,觉得文章不错可以关注公众号小奏技术

背景

最近在研究dubbotrace上下文传递,所以免不了要看看skywalking这一快的实现原理

skywalking version

  • 8.12.0

插件版本

  • dubbo-3.x-plugin

dubbo-3.x-plugin源码目录结构

源码整体流程

源码分析

可以看到主要有三个核心类 + 一个配置文件

DubboInstrumentation

这个类主要定义了什么时候触发增强,增强哪个类的哪个方法

增强哪个类

java 复制代码
public static final String ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";

@Override
protected ClassMatch enhanceClass() {
    return NameMatch.byName(ENHANCE_CLASS);
}

可以看到主要是增强MonitorFilter这个类

什么情况触发增强

java 复制代码
public static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";

public static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";

public static final String CONTEXT_ATTACHMENT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContextAttachment";

@Override
protected List<WitnessMethod> witnessMethods() {
    return Collections.singletonList(
        new WitnessMethod(
            CONTEXT_TYPE_NAME,
            named(GET_SERVER_CONTEXT_METHOD_NAME).and(
                returns(named(CONTEXT_ATTACHMENT_TYPE_NAME)))
        ));
}

这里主要定义了在org.apache.dubbo.rpc.RpcContext中必须存在方法getServerContext 并且他的返回值为org.apache.dubbo.rpc.RpcContextAttachment

我们简单对比下2.7.xdubbo的增强条件是什么

java 复制代码
    private static final String CONTEXT_TYPE_NAME = "org.apache.dubbo.rpc.RpcContext";

    private static final String GET_SERVER_CONTEXT_METHOD_NAME = "getServerContext";

    @Override
    protected List<WitnessMethod> witnessMethods() {
        return Collections.singletonList(new WitnessMethod(
            CONTEXT_TYPE_NAME,
            named(GET_SERVER_CONTEXT_METHOD_NAME).and(
                returns(named(CONTEXT_TYPE_NAME)))
        ));
    }

主要是org.apache.dubbo.rpc.RpcContext类中的getServerContext方法,返回值也是org.apache.dubbo.rpc.RpcContext

那么很明确了2.73.xgetServerContext的返回值被修改了。

增强的方法

在前面我知道增强的类是MonitorFilter

现在我们具体来看看增强哪个方法

java 复制代码
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
    return new InstanceMethodsInterceptPoint[] {
        new InstanceMethodsInterceptPoint() {
            @Override
            public ElementMatcher<MethodDescription> getMethodsMatcher() {
                return named(INTERCEPT_POINT_METHOD);
            }

            @Override
            public String getMethodsInterceptor() {
                return INTERCEPT_CLASS;
            }

            @Override
            public boolean isOverrideArgs() {
                return false;
            }
        }
    };
}

要增强的方法是

java 复制代码
public static final String INTERCEPT_POINT_METHOD = "invoke";

实现增强的类是

java 复制代码
public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.asf.dubbo3.DubboInterceptor";

所以接下来我们来看看实际实现增强的逻辑吧

DubboInterceptor

源码有点多。我们来一一分析

  1. 校验是不是Consumer
java 复制代码
boolean isConsumer = isConsumer(invocation);

private static boolean isConsumer(Invocation invocation) {
    Invoker<?> invoker = invocation.getInvoker();
    // As RpcServiceContext may not been reset when it's role switched from provider
    // to consumer in the same thread, but RpcInvocation is always correctly bounded
    // to the current request or serve request, https://github.com/apache/skywalking-java/pull/110
    return invoker.getUrl()
            .getParameter("side", "provider")
            .equals("consumer");
}

校验方式就通过urlParam获取side参数,默认为provider

  1. 获取RPC上下文RpcContextAttachment

  2. 如果是Consumer则创建ExitSpan,如果是Provider则创建EntrySpan

  3. 如果是Consumer则将skywalking上下文载体ContextCarrier放入dubborpc上下文RpcContextAttachment中,以便上下午在dubbo进行传递

java 复制代码
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
    next = next.next();
    attachment.setAttachment(next.getHeadKey(), next.getHeadValue());
    if (invocation.getAttachments().containsKey(next.getHeadKey())) {
        invocation.getAttachments().remove(next.getHeadKey());
    }
}
  1. 如果是Provider则从dubbo上下文RpcContextAttachment中获取Consumer的上下文恢复到skywalking上下文ContextCarrier

总结

总的来说dubbo这一快的上下文传递还是很简单的。总结为如下几个步骤

  1. 是否需要增强
  2. 如果是则判断是Provider还是Consumer
  3. 如果是Consumer则将上下文放入skywalking上下文ContextCarrier
  4. 如果是如果是Provider则从dubbo上下文RpcContextAttachment中获取Consumer的上下文恢复到skywalking上下文ContextCarrier

如果我们看其他实现trace传递的dubbo增强也是类似的实现原理,比如Tlog,感兴趣可以去看看,这里就不分析了

相关推荐
咖啡教室17 小时前
每日一个计算机小知识:Host
后端
咖啡教室18 小时前
每日一个计算机小知识:Bit和Byte(比特和字节)
后端
咖啡教室18 小时前
每日一个计算机小知识:Linux
linux·后端
IT_陈寒18 小时前
Vite 5个隐藏技巧让你的项目构建速度提升50%,第3个太香了!
前端·人工智能·后端
用户40993225021218 小时前
复杂查询总拖后腿?PostgreSQL多列索引+覆盖索引的神仙技巧你get没?
后端·ai编程·trae
凤山老林19 小时前
排序算法:详解插入排序
java·开发语言·后端·算法·排序算法
低音钢琴19 小时前
【SpringBoot从初学者到专家的成长18】SpringBoot中的数据持久化:JPA与Hibernate的结合
spring boot·后端·hibernate
paopaokaka_luck19 小时前
基于SpringBoot+Vue的社区诊所管理系统(AI问答、webSocket实时聊天、Echarts图形化分析)
vue.js·人工智能·spring boot·后端·websocket
李慕婉学姐20 小时前
Springboot黄河文化科普网站5q37v(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
道之极万物灭20 小时前
Go基础知识(一)
开发语言·后端·golang