Dubbo RPC 原理探究

栏目: Java · 发布时间: 7年前

内容简介:最近稍微研究了一点Dubbo的RPC原理,在这里记录一下笔记。主要是阅读源码:https://github.com/apache/incubator-dubbo,参考了Dubbo的官网开发者手册(写的非常好,就是内容略精简,初学者需要仔细消化):http://dubbo.apache.org/zh-cn/docs/dev/design.html,还有一个非常生动易懂的教程视频:https://www.bilibili.com/video/av30612478。本文首先介绍了Dubbo RPC中的核心概念与

最近稍微研究了一点Dubbo的RPC原理,在这里记录一下笔记。

主要是阅读源码:https://github.com/apache/incubator-dubbo,参考了Dubbo的官网开发者手册(写的非常好,就是内容略精简,初学者需要仔细消化):http://dubbo.apache.org/zh-cn/docs/dev/design.html,还有一个非常生动易懂的教程视频:https://www.bilibili.com/video/av30612478。

本文首先介绍了Dubbo RPC中的核心概念与契约,虽然画了幅示意图,但我估计不熟悉Dubbo的人第一眼看到后还是会一脸懵逼的。不过把RPC的核心流程源码读过几遍后,再回过头来看这段契约,会有更加深入的理解。

由于大部分情境下Dubbo是通过Spring配置使用的,因此接下来首先简单介绍了下服务解析的逻辑,然后从源码的角度分析了Dubbo的RPC流程,包括:服务引用、服务暴露、服务调用三个部分,每一部分都配了核心流程图和代码路径。

核心概念与契约

在Dubbo中有这么两个概念是最核心的:

  • Invoker:是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用。
  • Protocol:是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。

支撑起Dubbo RPC的就是如下这一段话:

当用户调用 refer() 所返回的 Invoker 对象的 invoke() 方法时,Protocol 需相应执行同 URL 远端 export() 传入的 Invoker 对象的 invoke() 方法。

画了一幅图来辅助理解这句话:

Dubbo RPC 原理探究

服务解析

所谓服务解析,就是在 Dubbo 初始化时进行,把 的标签解析并注册为 Spring Bean 的过程。

基于 Spring 的 Schema 扩展机制,这里不再展开,可以参考这篇文章:https://www.jianshu.com/p/8639e5e9fba6。

基于 dubbo.jar 内的 META-INF/spring.handlers 配置:

http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

Spring 在遇到 dubbo 名称空间时,会回调 DubboNamespaceHandler:

/**
* DubboNamespaceHandler
*
* @export
*/

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

static {
       Version.checkDuplicate(DubboNamespaceHandler.class);
}

@Override
public void init() {
      registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
      registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
      registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
      registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
      registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
      registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
      registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
      registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
      registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
      registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}

}

所有 dubbo namespace下的的标签,都统一用 DubboBeanDefinitionParser 进行解析,基于一对一属性映射,将 XML 标签解析为对应的 Bean 对象,再注册到容器里。

和RPC核心流程密切相关的标签:

  • 解析为 ReferenceBean
  • 解析为 ServiceBean

服务引用

所谓服务引用,就是服务的消费端从Protocol中拿到正确的Invoker的过程,对应核心契约图的左半部分,按照契约的说法,接下来消费端对这个Invoker发起调用,就会达到调用远端同URL暴露出来的Invoker的效果了。

Dubbo RPC 原理探究

关键代码路径:

  • ReferenceBean#getObject:ReferenceBean实现了Spring的FactoryBean接口,因此IOC容器想要获取ReferenceBean的实例时会去调用getObject方法来获取。
  • ReferenceConfig#get:第一次调用时会触发初始化逻辑,之后直接返回创建好的实例引用。
  • ReferenceConfig#createProxy
    Dubbo RPC 原理探究

这里的两行代码分别解析:

  1. Dubbo基于扩展点的自适应机制(http://dubbo.apache.org/zh-cn/docs/dev/SPI.html),会自动识别URL中的协议类型,并调用合适的Protocol实现类,在这里我们默认用的是Dubbo协议,因此会调用DubboProtocol进行服务引用:

    Dubbo RPC 原理探究
  2. ProxyFactory同样是扩展点,这里默认使用了JavassistProxyFactory的实现:

    Dubbo RPC 原理探究

    可以看到这里创建的代理,把对接口方法的调用交给了 InvokerInvocationHandler这个类去处理。这里先不展开,可以留待分析服务调用时再看。

服务暴露

所谓服务暴露,就是服务提供方把代理了真正实现类的Invoker暴露给Protocol的过程,对应核心契约的右半部分。

Dubbo RPC 原理探究

关键代码路径:

  • ServiceBean#onApplicationEvent
  • ServiceConfig#export
  • ……
  • ServiceConfig#doExportUrlsFor1Protocol
    Dubbo RPC 原理探究

展开看高亮出的两段逻辑:

  1. 同服务引用一样,这里的ProxyFactory依旧是扩展点,具体实现如下,可以看到这里创建一个AbstractProxyInvoker,当该Invoker的doInvoke方法被调用时,就会调用真正实现类 ref 里的方法:

    Dubbo RPC 原理探究

2.同样,Protocol也是扩展点,默认采用Dubbo实现:

Dubbo RPC 原理探究

export方法干了两件事:

  • 将上一步拿到的Invoker export出去,然后创建 DubboExporter实例并存储在 exporterMap 里,Exporter并没有什么玄机,就是一个存储了Invoker实例及其他各种信息的容器,用于之后获取Invoker用。
  • 打开服务端口,并注册ExchangeHandler,用于后续响应客户端网络请求,响应逻辑这里先不展开。

#服务调用 服务调用分两部分来分析:客户端发起调用、服务端响应调用。

客户端发起调用

Dubbo RPC 原理探究

按照之前服务引用代码的分析,客户端对拿到的Bean发起调用时,会被 JavassistProxyFactory#getProxy 创建的代理接管,把请求交给InvokerInvocationHandler处理:

Dubbo RPC 原理探究

按照之前服务引用代码的分析,这里调用的Invoker是调用refprotocol#refer拿到的,是一个DubboInvoker,因此会进入下面的逻辑,其实就是发起一次网络请求,拿到返回值: Dubbo RPC 原理探究

这样,就通过代理机制,就把客户端发起的本地请求转换为了对服务端的网络请求。

服务端响应调用

上文里服务提供端暴露服务时,在openServer逻辑里,注册了一个ExchangeHandler用于响应客户端的网络请求 Dubbo RPC 原理探究

Dubbo RPC 原理探究

  • getInvoker方法是通过exporterMap获取之前暴露的 Invoker 实例,然后调用其invoke方法。

  • 由前文服务暴露部分(JavassistProxyFactory#getInvoker )里的逻辑可知:当DubboInvoker的doInvoke方法被调用时,就会调用真正实现类 ref 里的方法,这样就触达到了服务的提供者。

结语

以上就是Dubbo RPC的核心流程逻辑了,这次研究时有很多逻辑被我当做了黑盒来处理,比如扩展点加载、负载均衡、网络请求、线程模型等……实际上一次RPC过程远比上述描述的复杂,按照官网的说明,RPC过程的流程如下所示: Dubbo RPC 原理探究 什么时候真正吃透了这张图,才敢说自己懂了Dubbo RPC吧。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Clean Architecture

Clean Architecture

Robert C. Martin / Prentice Hall / 2017-9-20 / USD 34.99

Practical Software Architecture Solutions from the Legendary Robert C. Martin (“Uncle Bob”) By applying universal rules of software architecture, you can dramatically improve developer producti......一起来看看 《Clean Architecture》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具