首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

一文讲明Dubbo Remoting模块

设为“星标”,好文章不错过!

dubbo-remoting 模块提供了多种客户端和服务端通信功能。

最底层部分即为 Remoting 层

包括 Exchange、Transport和Serialize 三层。本文主要描述 Exchange 和 Transport 两层。

Dubbo 整体架构设计图

Dubbo直接集成已有的第三方网络库,如Netty、Mina、Grizzly 等 NIO 框架。

dubbo-remoting-zookeeper使用 Apache Curator 实现了与 Zookeeper 的交互。

dubbo-remoting-api 模块

是其他  模块的顶层抽象,其他 dubbo-remoting 子模块都是依赖第三方 NIO 库实现 dubbo-remoting-api 模块。

buffer 包

定义了缓冲区相关的接口、抽象类以及实现类。在各个 NIO 框架中都有自己的缓冲区实现。但这里的 buffer 包在更高层面,抽象了各个 NIO 框架的缓冲区,同时也提供了一些基础实现。

exchange 包

抽象了 Request 和 Response,并为其添加很多特性。这是整个远程调用核心部分。

transport 包

抽象网络传输层,但只负责抽象单向消息传输,即请求消息由 Client 端发出,Server 端接收;响应消息由 Server 端发出,Client端接收。有很多网络库可以实现网络传输,如Netty, transport 包是在网络库上层的一层抽象。

传输层核心接口

“端点(Endpoint)”,可通过一个  和  唯一确定一个端点,两端点间会创建  连接,双向传输数据。Dubbo 将 Endpoint 之间的 TCP 连接抽象为(Channel)通道,将发起请求的 Endpoint 抽象为Client,接收请求的 Endpoint 抽象为Server。

Endpoint 接口

getXXX() 用于获得 Endpoint 本身的一些属性,如Endpoint 的本地地址、关联的 URL 信息以及底层 Channel 关联的 ChannelHandler。

send() 负责数据发送

close() 及 startClose() 用于关闭底层 Channel

isClosed() 方法用于检测底层 Channel 是否已关闭

Channel

对 Endpoint 双方连接的抽象,就像传输管道。消息发送端往 Channel 写入消息,接收端从 Channel 读取消息。

接口的定义

继承 Endpoint 接口,也具备开关状态以及发送数据能力

可在 Channel 上附加 KV 属性

ChannelHandler

注册在 Channel 上的消息处理器,接口的定义

注解表明该接口是一个扩展点。

有一类特殊的 ChannelHandler 专门负责实现编解码功能,从而实现字节数据与有意义的消息之间的转换,或是消息之间的相互转换

该接口也是一个扩展接口,encode()、decode() 被 @Adaptive 注解修饰,也就会生成适配器类,其中会根据 URL 中的 codec 值确定具体的扩展实现类。

DecodeResult 这个枚举是在处理 TCP 传输时粘包和拆包使用的,例如,当前能读取到的数据不足以构成一个消息时,就会使用  枚举。

接下来看Client 和 RemotingServer 两个接口,分别抽象了客户端和服务端,两者都继承了 Channel、Resetable 等接口,也就是说两者都具备了读写数据能力。

Client、RemotingServer

都继承了 Endpoint,只是在语义上区分请求和响应职责,都具备发送数据能力。

Client 和 Server 的主要区别:

Client 只能关联一个 Channel

Server 可接收多个 Client 发起的 Channel 连接,所以在 RemotingServer 接口中定义了查询 Channel 的相关方法

Transporter

Dubbo 在 Client 和 Server 之上又封装了一层Transporter 接口

注解扩展接口,默认使用“netty”扩展名

注解表示动态生成适配器类,会先后根据“server”“transporter”的值确定  的扩展实现类,先后根据“client”“transporter”的值确定 Client 接口的扩展实现。

几乎对每个支持的 NIO 库,都有接口实现

为什么要单独抽象出 Transporter层,不直接让上层使用 Netty?

正是利用了依赖反转原则(DIP),Netty、Mina、Grizzly 等 NIO 库对外接口和使用方式不同,若在上层直接依赖 Netty 或Grizzly,就依赖了具体的 NIO 库,而非依赖一个有传输能力的抽象,后续要切换实现的话,就需修改依赖和接入的相关代码。

有了 Transporter 层,就可通过 Dubbo SPI 修改使用的具体 Transporter 扩展实现,从而切换到不同 Client 和 RemotingServer 实现,切换底层 NIO 库,而无须修改代码。即使有更先进的 NIO 库出现,也只需开发相应的  实现模块提供 Transporter、Client、RemotingServer 等核心接口的实现,即可接入,完全符合开放封闭原则。

Transporters

不是一个接口,而是门面类,封装了 Transporter 对象的创建(通过 Dubbo SPI)以及 ChannelHandler 的处理

在创建 Client 和 RemotingServer 的时候,可指定多个 ChannelHandler 绑定到 Channel 来处理其中传输的数据。Transporters.connect() 方法和 bind() 方法中,会将多个 ChannelHandler 封装成一个 ChannelHandlerDispatcher 对象。

ChannelHandlerDispatcher 也是 ChannelHandler 接口的实现类之一,维护了一个 CopyOnWriteArraySet 集合,它所有的 ChannelHandler 接口实现都会调用其中每个 ChannelHandler 元素的相应方法。另外,ChannelHandlerDispatcher 还提供了增删该 ChannelHandler 集合的相关方法。

Endpoint 接口抽象了“端点”的概念,这是所有抽象接口的基础

上层使用方会通过 Transporters 门面类获取到 Transporter 的具体扩展实现,然后通过 Transporter 拿到相应的 Client 和 RemotingServer 实现,就可以建立(或接收)Channel 与远端进行交互

无论是 Client 还是 RemotingServer,都会使用 ChannelHandler 处理 Channel 中传输的数据,其中负责编解码的 ChannelHandler 被抽象出为 Codec2 接口。

Transporter 层整体结构图

参考

https://dubbo.apache.org/en-us/docs/dev/design.html

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201016A0002N00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券