Dubbo 是什么
官方术语是这样来定义 Dubbo 的:
Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑,以改变框架的默认行为来满足自己的业务需求。
虽然说 Dubbo 具备的能力很强大,但往往我们一开始来使用 Dubbo 基本上都是使用 Dubbo 的远程服务调用的能力,Dubbo 能够为我们做到:
- 只需简单配置就能实现透明化的远程方法调用,就像调用本地方法一样来调用远程方法
- 软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点
- 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者
框架整体设计:
上面图例来自官方文档,这张图基本上把 Dubbo 的整个框架核心内容都囊括进去了,左边淡蓝色部分属于消费方 Consumer 使用到的接口和类,右边淡绿色是提供方 Provider 使用到的接口和类,中轴线是双方都会用到的接口和类。
需要注意的是对于 Consumer 和 Provider,它只是个抽象的概念,目的是能够更直观的说明哪些类分属于客户端与服务器端,不用 Client 和 Server 的原因是 Dubbo 在很多场景下都使用 Provider, Consumer, Registry, Monitor 划分逻辑拓扑节点,保持统一概念。
- config 配置层:对外配置接口,以
ServiceConfig
,ReferenceConfig
为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类 - proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以
ServiceProxy
为中心,扩展接口为ProxyFactory
。Proxy 层封装了所有接口的透明化代理,而在其它层都以 Invoker 为中心,只有到了暴露给用户使用时,才用 Proxy 将 Invoker 转成接口,或将接口实现转成 Invoker,也就是去掉 Proxy 层 RPC 是可以 Run 的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。 - registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为
RegistryFactory
,Registry
,RegistryService
。Registry 实际上并不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起 - cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以
Invoker
为中心,扩展接口为Cluster
,Directory
,Router
,LoadBalance
。Cluster 是外围概念,目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。 - monitor 监控层:RPC 调用次数和调用时间监控,以
Statistics
为中心,扩展接口为MonitorFactory
,Monitor
,MonitorService
。实际上并不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起 - protocol 远程调用层:封装 RPC 调用,以
Invocation
,Result
为中心,扩展接口为Protocol
,Invoker
,Exporter
。Protocol 是核心层,也就是只要有 Protocol + Invoker + Exporter 就可以完成非透明的 RPC 调用,然后在 Invoker 的主过程上 Filter 拦截点 - exchange 信息交换层:封装请求响应模式,同步转异步,以
Request
,Response
为中心,扩展接口为Exchanger
,ExchangeChannel
,ExchangeClient
,ExchangeServer
。Exchange 层是在传输层之上封装了 Request-Response 语义 - transport 网络传输层:抽象 mina 和 netty 为统一接口,以
Message
为中心,扩展接口为Channel
,Transporter
,Client
,Server
,Codec
。Transport 层只负责单向消息传输,是对 Mina, Netty, Grizzly 的抽象,它也可以扩展 UDP 传输 - serialize 数据序列化层:可复用的一些工具,扩展接口为
Serialization
,ObjectInput
,ObjectOutput
,ThreadPool
依赖关系
图例说明:
- 图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层或模块,蓝色的表示与业务有交互,绿色的表示只对 Dubbo 内部交互。
- 图中背景方块 Consumer, Provider, Registry, Monitor 代表部署逻辑拓扑节点。
- 图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用。
- 图中只包含 RPC 的层,不包含 Remoting 的层,Remoting 整体都隐含在 Protocol 中。
Consumer、Provider,Register,Monitor 间调用关系说明:
- 服务提供者 Provider 启动时向注册中心 Register 注册自己提供的服务。
- 服务消费者 Consumer 在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心 Monitor(异步)。
远程调用细节
首先 ServiceConfig
类拿到对外提供服务的实际类 ref,然后通过 ProxyFactory
类的 getInvoker
方法使用 ref 生成一个 AbstractProxyInvoker
实例,到这一步就完成具体服务到 Invoker
的转化。接下来就是 Invoker
转换到 Exporter
的过程(上图中的红色部分),这一过程对于有不同的实现有不同的方式,如果是 Dubbo 实现,主要发生在DubboProtocol
类的 export
方法,它主要是打开 socket 侦听服务,并接收客户端发来的各种请求,通讯细节由 Dubbo 自己实现。
首先 ReferenceConfig
类的 init
方法调用 Protocol
的 refer
方法生成 Invoker
实例(上图中的红色部分),这是服务消费的关键。接下来把 Invoker
转换为客户端需要的接口。
Invoker 是什么
由于 Invoker
是 Dubbo 领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。从上面暴露服务和消费服务的过程中也可以看出来, Invoker
渗透在整个实现代码里,对于刚开始接触 Dubbo 的人很容易就给搞混了。 Invoker 是 Dubbo 中的实体域,也就是真实存在的。其他模型都向它靠拢或转换成它,它也就代表一个可执行体,可向它发起 invoke 调用。在服务提供方,Invoker 用于调用服务提供类,在服务消费方,Invoker 用于执行远程调用。
领域模型
在 Dubbo 的核心领域模型中:
- Protocol 是服务域,它是 Invoker 暴露和引用的主功能入口,它负责 Invoker 的生命周期管理。
- Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
- Invocation 是会话域,它持有调用过程中的变量,比如方法名,参数等。