Dubbo把各种复杂的对象以及错综复杂的关系抽象出来两个简单易理解的角色:服务提供者(Provider)和消费者(Consumer),先来看整体分层的架构:
Dubbo框架设计一共划分了10个层,而最上面的Service层是留给实际想要使用Dubbo开发分布式服务的开发者实现业务逻辑的接口层。
图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口, 位于中轴线上的为双方都用到的接口。
根据官方提供的,对于上述各层之间关系的描述,如下所示:
- 在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流程,可以参照以下模型:
图中,蓝色的表示与业务有交互,绿色的表示只对Dubbo内部交互。上述图所描述的调用流程如下:
- 服务提供方发布服务到服务注册中心,注册中心有新的服务会notify服务消费者;
- 服务消费方从服务注册中心订阅服务,如果没有收到服务,则会retry;
- 服务消费方调用已经注册的可用服务;
Monitor是一个监控,用来记录服务消费者调用服务提供者的次数,虚线表明Consumer 和Provider通过异步的方式发送消息至Monitor,
Consumer和Provider会将信息存放在本地磁盘,平均1min会发送一次信息。Monitor在整个架构中是可选的(图中的虚线并不是可选的意思),
Monitor功能需要单独配置,但不论配置是否,Monitor的挂掉并不会影响服务的调用。
服务调用的整个流程如下:
容器启动加载dubbo配置文件的时候首先遇到dubbo的命名空间时会回调DubboNamespaceHandler类初始化配置文件中各个对象,加载到dubbo的标签时由DubboBeanDefinitionParser类统一解析,基于一对一属性映射,将XML标签解析为Bean对象。然后由ServiceConfig.export()或者ReferenceConfig.get()方法初始化将Bean对象转换成URL,Bean属性转成了URL参数,这些URL参数再交由Protocol,基于Protocol扩展点的Adaptive机制,根据URL的协议头,进行不同协议的服务暴露和引用。
对于Provider一方详细的流程为:
provider服务提供方:向注册中心暴露服务,需要将服务的IP和端口都暴露给注册中心,过程如下:
1)由ServiceConfig的expor()方法将对象转换成URL参数,格式如下:
registry://registry-host/com.alibaba.dubbo.registry.RegistryService? export=URL.encode(“dubbo://service-host/com.xxx.TxxService?version=1.0.0”)。
2)再由Registry层基于扩展点的Adaptive机制,通过URL的“registry://”协议头识别,调用RegistryProtocol的export方法,将参数中提供者URL注册到注册中心,
然后再传给Protocol层,由DubboProtocol类执行export方法,其主要是打开socket侦听服务,并接收客户端发来的各种请求,最后基于Protocol扩展点进行暴露URL
Dubbo://service-host/com.xxx.TxxService?version=1.0.0
调用架构层(本篇第一张图)流程可参考:
对于Consumer一方流程大体类似:
Consumer服务引用方: 从注册中心发现引用服务,过程如下:
1)由ReferenceConfig的get()方法初始化将Bean对象转成URL,格式如下:
registry://registry-host/com.alibaba.dubbo.registry.RegistryService? refer=URL.encode(“consumer://consumer-host/com.foo.FooService?version=1.0.0”)
2)再由Registry层基于扩展点的Adaptive机制,通过URL的“registry://”协议头识别,就会调用RegistryProtocol的refer方法,基于refer参数总的条件,查询提供者URL,如:
Dubbo://service-host/com.xxx.TxxService?version=1.0.0,但查询到的提供者引用很可能会有多个,于是RegistryProtocol将多个提供者引用通过Cluster扩展点,利用软负载均衡,伪装成单个提供者返回。
调用架构层(本篇第一张图)流程可参考:
Dubbo提供的注册中心有如下几种类型可供选择:
- Multicast注册中心
- Zookeeper注册中心
- Redis注册中心
- Simple注册中心
Dubbo提供的协议支持
Dubbo支持多种协议,如下所示:
- Dubbo协议
- Hessian协议
- HTTP协议
- RMI协议
- WebService协议
- Thrift协议
- Memcached协议
- Redis协议
在通信过程中,不同的服务等级一般对应着不同的服务质量,那么选择合适的协议便是一件非常重要的事情。你可以根据你应用的创建来选择。例如,使用RMI协议,一般会受到防火墙的限制,所以对于外部与内部进行通信的场景,就不要使用RMI协议,而是基于HTTP协议或者Hessian协议。
Dubbo提供4种负载均衡方式:
- Random,随机,按权重配置随机概率,调用量越大分布越均匀,默认是这种方式
- RoundRobin,轮询,按权重设置轮询比例,如果存在比较慢的机器容易在这台机器的请求阻塞较多
- LeastActive,最少活跃调用数,不支持权重,只能根据自动识别的活跃数分配,不能灵活调配
- ConsistentHash,一致性hash,对相同参数的请求路由到一个服务提供者上,如果有类似灰度发布需求可采用
dubbo的负载均衡机制是在客户端调用时通过内存中的服务方信息及配置的负责均衡策略选择,如果对自己系统没有一个全面认知,建议先采用random方式。
参考链接:
- https://github.com/alibaba/dubbo
- http://shiyanjun.cn/archives/325.html
- http://blog.csdn.net/chao_19/article/details/51764150
- http://blog.csdn.net/quhongwei_zhanqiu/article/details/41651205
- http://blog.csdn.net/xcylive520/article/details/52347110