Dubbo |ˈdʌbəʊ| 分布式初体验 —— 第四章 Dubbo 原理
1. RPC 原理
一次完整的 RPC 调用流程(同步调用)如下:
- 服务消费者(Client)以本地调用方式调用服务
- ClientStub 接收到消息后负责将方法、参数组装成能够进行网络传输的消息体
- ClientStub 找到服务器地址,并将消息发送到服务端
- ServerStub 收到消息后进行解码
- ServerStub 根据解码结果调用本地的服务
- 本地服务执行并将结果返回 ServerStub
- ServerStub 将结果打包成消息
- ServerStub 将消息发送至消费者
- ClientStub 接收到消息,并进行解码
- 服务消费者得到最终结果
RPC 框架的目标就是要 2 ~ 9 这些流程都封装起来,这些细节对于用户来说都是透明的,不可见的
2. Netty 通信原理
Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端。它极大简化了 TCP 和 UDP 套接字服务器等网络编程
BIO(Blocking IO,阻塞式 IO):
NIO(Non-Blocking IO,非阻塞式 IO):
Selector 一般称为选择器,也可翻译为多路复用器
四种状态:Connect
连接就绪、Accept
接受就绪、Read
读就绪、Write
写就绪
Netty 基本原理:
3. Dubbo 原理
3.1. Dubbo 原理——框架设计
整体设计:
图例说明:
- 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。
- 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。
- 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。
- 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。
各层说明:
- Config 配置层: 对外配置接口,以
ServiceConfig
,ReferenceConfig
为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类 - Proxy 服务代理层: 服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以
ServiceProxy
为中心,扩展接口为ProxyFactory
- Registry 注册中心层: 封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为
RegistryFactory
,Registry
,RegistryService
- Cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以
Invoker
为中心,扩展接口为Cluster
,Directory
,Router
,LoadBalance
- Monitor 监控层: RPC 调用次数和调用时间监控,以
Statistics
为中心,扩展接口为MonitorFactory
,Monitor
,MonitorService
- Protocol 远程调用层: 封装 RPC 调用,以
Invocation
,Result
为中心,扩展接口为Protocol
,Invoker
,Exporter
- Exchange 信息交换层: 封装请求响应模式,同步转异步,以
Request
,Response
为中心,扩展接口为Exchanger
,ExchangeChannel
,ExchangeClient
,ExchangeServer
- Transport 网络传输层: 抽象 mina 和 netty 为统一接口,以
Message
为中心,扩展接口为Channel
,Transporter
,Client
,Server
,Codec
- Serialize 数据序列化层: 可复用的一些工具,扩展接口为
Serialization
,ObjectInput
,ObjectOutput
,ThreadPool
关系说明:
- 在 RPC 中,Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点。
- 图中的 Consumer 和 Provider 是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓扑节点,保持统一概念。
- 而 Cluster 是外围概念,所以 Cluster 的目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。
- Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。
- 而 Remoting 实现是 Dubbo 协议的实现,如果你选择 RMI 协议,整个 Remoting 都不会用上,Remoting 内部再划为 Transport 传输层和 Exchange 信息交换层,Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,它也可以扩展 UDP 传输,而 Exchange 层是在传输层之上封装了 Request-Response 语义。
- Registry 和 Monitor 实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。
模块分包:
模块说明:
dubbo-common
公共逻辑模块: 包括 Util 类和通用模型。dubbo-remoting
远程通讯模块:相当于 Dubbo 协议的实现,如果 RPC 用 RMI协议则不需要使用此包。dubbo-rpc
远程调用模块: 抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。dubbo-cluster
集群模块: 将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。dubbo-registry
注册中心模块: 基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。dubbo-monitor
监控模块: 统计服务调用次数,调用时间的,调用链跟踪的服务。dubbo-config
配置模块: 是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。dubbo-container
容器模块: 是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。
整体上按照分层结构进行分包,与分层的不同点在于:
- container 为服务容器,用于部署运行服务,没有在层中画出。
- protocol 层和 proxy 层都放在 rpc 模块中,这两层是 rpc 的核心,在不需要集群也就是只有一个提供者时,可以只使用这两层完成 rpc 调用。
- transport 层和 exchange 层都放在 remoting 模块中,为 rpc 调用的通讯基础。
- serialize 层放在 common 模块中,以便更大程度复用。
依赖关系:
图例说明:
- 图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互。
- 图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点。
- 图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用。
- 图中只包含 RPC 的层,不包含 Remoting 的层,Remoting 整体都隐含在 Protocol 中。
3.2. Dubbo 原理——启动解析、加载配置信息
sequenceDiagram participant 容器启动 participant DubboNameSpaceHandler participant DubboBeanDefinitionParser participant ServiceBean participant ServiceConfig participant ProxyFactory participant Protocol participant Invoker participant Exporter participant DubboExporter participant RegistryExporter 容器启动 ->> DubboNameSpaceHandler: 解析配置文件 DubboBeanDefinitionParser ->> DubboBeanDefinitionParser: ApplicationConfig DubboBeanDefinitionParser ->> DubboBeanDefinitionParser: RegistryConfig DubboNameSpaceHandler ->> DubboNameSpaceHandler: 创建Dubbo标签解析器 DubboNameSpaceHandler ->> DubboBeanDefinitionParser: 解析Dubbo标签 DubboBeanDefinitionParser ->> DubboBeanDefinitionParser: ...... DubboBeanDefinitionParser ->> ServiceBean: ServiceBean解析 ServiceBean ->> ServiceBean: 容器创建完成,触发ContextRefreshEvent ServiceBean ->> ServiceConfig: export(),暴露服务 ServiceConfig ->> ServiceConfig: doExportUrls() ServiceConfig ->> ProxyFactory: doExportFor1Protocol() ProxyFactory ->> Invoker: getInvoker() Exporter ->> DubboExporter: 开启服务器 DubboExporter ->> DubboExporter: openServer() Protocol ->> Exporter: protocol.export(invoker) Exporter ->> RegistryExporter: 注册服务到注册中心 RegistryExporter ->> RegistryExporter: ProvidredConsumerRegTable.registerProvider
3.3. Dubbo 原理——服务暴露
展开总设计图左边服务提供方暴露服务的蓝色初始化链,时序图如下:
sequenceDiagram participant Actor participant ServiceConfig participant ProxyFactory participant Invoker participant Protocol participant Exporter participant Transporter participant Server participant ExporterListener participant Registry Actor ->> ServiceConfig: 1. export() ServiceConfig ->> ProxyFactory: 2.createInvoker() ProxyFactory ->> Invoker: 3.() ServiceConfig ->> Protocol: 4. export() Protocol ->> Exporter: 5. () Exporter ->> Transporter: 6. bind() Transporter ->> Server: 7. () Protocol ->> ExporterListener: 8. exported() ExporterListener ->> Registry: 9. register() Actor ->> ServiceConfig: 10. unecport() ServiceConfig ->> Exporter: 11. unexport() Exporter ->> Invoker: 12. destroy() Exporter ->> ExporterListener: 13. unexported() ExporterListener ->> Registry: 14. unregister()
3.4. Dubbo 原理——服务引用
展开总设计图右边服务消费方引用服务的蓝色初始化链,时序图如下:
sequenceDiagram participant Actor participant ReferenceConfig participant RegistryProtocol participant Registry participant Directory participant Cluster participant Protocol participant Invoker participant Transporter participant Client participant InvokerListener participant ProxyFactory Actor ->> ReferenceConfig: 1. get()\ ReferenceConfig ->> RegistryProtocol: 2. refer() RegistryProtocol ->> Registry: 3. subscribe() Registry ->> Directory: 4. notified() Directory ->> Protocol: 5. refer() Protocol ->> Invoker: 6.() Invoker ->> Transporter: 7. connect() Transporter ->> Client: 8. () Protocol ->> InvokerListener: 9. referred() RegistryProtocol ->> Cluster: 10. merge() Cluster ->> Invoker: 11. () ReferenceConfig ->> ProxyFactory: 12. createProxy() Actor ->> ReferenceConfig: 13. destroy() ReferenceConfig ->> Invoker: 14. destroy() Invoker ->> Registry: 15. unsubscribe() Invoker ->> Directory: 16. destroy() Directory ->> Invoker: 17. destroy() Invoker ->> Client: 18. close() Invoker ->> InvokerListener: 19. destroyed()
3.5. Dubbo 原理——服务调用
展开总设计图的红色调用链,如下: