本文写作时,dubbo最高版本是V2.6.0。 写这篇文章主要想回答以下4个问题:
一、dubbo是什么?完成了哪些主要需求?
二、dubbo适用于什么场景?
三、dubbo的总体架构是什么样的?
四、dubbo调用的过程是什么样的?
下面就一一道来。
一、dubbo是什么?完成了哪些主要需求?
dubbo是一个面向服务治理(SOA)的分布式RPC框架。
它主要实现了以下一些需求:
RPC方面:
实现了基本的RPC过程,开发了DubboProtocol作为默认的实现,并集成了Hession,RMI,HTTP,WebService,Thrift(被改造,与原Thrift不兼容),Rest等远程过程调用框架。基本组成为:Protocol(默认dubbo),Invoker,Transporter(默认netty),Codec2(默认Hession2编码)。
编解码方面提供了Hession2(默认,阿里修改过的hessian lite)、dubbo、Java、JSON、Thrift(与原Thrift不兼容)、Kryo、FST序列化。
DubboProtocol实现了同步调用、异步请求、回调方法设置、本地调用等等灵活的调用特性。
服务治理方面:
1、实现了集群、容错、负载均衡及路由策略
2、实现了注册功能,完成提供者、消费者注册、订阅通知策略等;
3、对外提供了服务提供者、消费者配置信息、调用链、依赖关系的展现接口,并可以对服务提权、降级,配置路由信息等针对服务的治理手段;
4、开发了服务管理控制台dubbo-admin,可以在此查看服务相关注册信息,对服务实施治理;
5、开发了服务监控台dubbo-monitor,可查看服务实时调用情况,包括调用次数,调用时间,吞吐量等统计信息,实时查看服务的健康状况,作为服务治理手段的依据。
二、dubbo适用于什么场景?
1、业务中需要高吞吐量、复杂的RPC调用,有服务治理需求的场景;
2、有轻量级微服务化需求的场景;
下面引用dubbo用户手册的需求描述来说明什么情况下需要用到dubbo:
在大规模服务化之前,应用可能只是通过 RMI 或 Hessian 等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过 F5 等硬件进行负载均衡。
当服务越来越多时,服务 URL 配置管理变得非常困难,F5 硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。并通过在消费方获取服务提供方地址列表,实现软负载均衡和 Failover,降低对 F5 硬件负载均衡器的依赖,也能减少部分成本。
当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。 这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。
接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器? 为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
以上是 Dubbo 最基本的几个需求。
三、dubbo的总体架构是什么样的?
调用关系说明:
0、服务容器在启动时启动、加载服务提供者;
1、启动时,服务提供者向注册中心注册服务;
2、启动时,服务消费者向注册中心订阅服务;
3、注册中心给消费者返回服务提供者的地址列表,的提供者服务有什么变动,将用长连接推送变动数据给订阅者;
4、服务消费者发起对提供者服务的调用,提供者返回调用结果给消费者;
5、服务消费者和提供者在内存中累计调用次数和调用时间,每分钟发送一次统计数据给监控中心Monitor,供监控中心统计查询。
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远程通讯模块,主要实现DubboProtocol底层通讯细节(用RMI协议,此包没用),包含的接口有:Transaction(传输层),Exchange数据交换层等;
- dubbo-rpc远程调用模块,实现Protocol,Invoker, Exporter等上层协议接口定义,实现DubboProtocol协议的上层实现,以及DubboCodec类(dubbo编码)实现;封装了Hession协议、RMI协议、Http协议、WebService协议、Rest协议、Thrift等协议的实现;抽象了动态代理,只包含一对一的调用,不关心集群的管理。
- dubbo-cluster集群模块,将多个提供方伪装成一个服务方,定义了Cluster集群接口、容错接口、Loadbalance负载均衡接口、Route接口,Directry目录接口,并提供了以上接口的各种实现。集群的地址列表可以是静态配置的,也可以是由注册中心下发。
- dubbo-register注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。
- dubbo-config配置模块,实现服务提供者和消费者的配置定义加载。
- dubbo-container容器模块,实现了启动时的服务提供者和消费者启动、加载、初始化。一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。
- dubbo-monitor 监控模块:统计服务调用次数,调用时间的,调用链跟踪的服务。
整体上按照分层结构进行分包,与分层的不同点在于:
- container 为服务容器,用于部署运行服务,没有在层中画出。
- protocol 层和 proxy 层都放在 rpc 模块中,这两层是 rpc 的核心,在不需要集群也就是只有一个提供者时,可以只使用这两层完成 rpc 调用。
- transport 层和 exchange 层都放在 remoting 模块中,为 rpc 调用的通讯基础。
- serialize 层放在 common 模块中,以便更大程度复用。
四、dubbo调用的过程是什么样的?
调用链:
展开总设计图的红色调用链,如下:
暴露服务时序图:
展开总设计图左边服务提供方暴露服务的蓝色初始化链,时序图如下:
引用服务时序图:
展开总设计图右边服务消费方引用服务的蓝色初始化链,时序图如下:
注:以上大量引用了dubbo的develop手册的文字和图片内容。
来源:oschina
链接:https://my.oschina.net/u/4389765/blog/4236963