模块关系
模块说明
- 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模块中,以便更大程度复用。
各层说明
- config,配置层,对外配置接口,以ServiceConfig, ReferenceConfig为中心,可以直接new配置类,也可以通过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实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。
依赖关系:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:monitor address="${dubbo.monitor.address}"/>
<dubbo:application name="应用名" owner=""/>
<dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}" client="zkclient" group="${dubbo.zk.group}" file="dubbo-reg-zk.cache"/>
<dubbo:protocol name="dubbo" port="${dubbo.service.provider.port}" threadpool="cached" threads="${dubbo.service.provider.threads:200}"/>
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" />
<bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />
</beans>
Spring提供了可扩展Schema的支持,解析自定义的xml文件,然后转化为配置对象。主要步骤:
- 设计配置属性和JavaBean
- 编写xsd文件
- 编写NamespaceHandler和BeanDefinitionParser完成解析工作
- 编写spring.handlers和spring.schemas串联起所有部件
- 开始使用bean实例对象
dubbo框架实现的子类分别是 com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler和com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser将xml配置转换为类实例对象。
参考例子:http://blog.csdn.net/cutesource/article/details/5864562
dubbo的xml配置与对应业务类的映射关系:
com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
说明:
org.springframework.beans.factory.xml.NamespaceHandlerSupport.registerBeanDefinitionParser(String, BeanDefinitionParser)
a)第一个参数,表示子节点名,比如“dubbo:service/” 中的service
b) 第二个参数,表示节点的解析器
schema格式 | 类模板 | 内部属性 | 描述 |
---|---|---|---|
dubbo:service/ | com.alibaba.dubbo.config.ServiceConfig | 链接 | 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心 |
dubbo:reference/ | com.alibaba.dubbo.config.ReferenceConfig | 同上 | 引用配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。 |
dubbo:protocol/ | com.alibaba.dubbo.config.ProtocolConfig | 同上 | 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受 |
dubbo:application/ | com.alibaba.dubbo.config.ApplicationConfig | 同上 | 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者 |
dubbo:module/ | com.alibaba.dubbo.config.ModuleConfig | 同上 | 模块配置,用于配置当前模块信息,可选。 |
dubbo:registry/ | com.alibaba.dubbo.config.RegistryConfig | 同上 | 注册中心配置,用于配置连接注册中心相关信息 |
dubbo:monitor/ | com.alibaba.dubbo.config.MonitorConfig | 同上 | 监控中心配置,用于配置连接监控中心相关信息,可选。 |
dubbo:provider/ | com.alibaba.dubbo.config.ProviderConfig | 同上 | 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。 |
dubbo:consumer/ | com.alibaba.dubbo.config.ConsumerConfig | 同上 | 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。 |
dubbo:method/ | com.alibaba.dubbo.config.MethodConfig | 同上 | 方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息 |
dubbo:argument/ | com.alibaba.dubbo.config.ArgumentConfig | 同上 | 用于指定方法参数配置。 |
类依赖关系:
注意:只有group,interface,version是服务的匹配条件,三者决定是不是同一个服务,其它配置项均为调优和治理参数。
所有配置最终都将转换为URL表示,并由服务提供方生成,经注册中心传递给消费方,各属性对应URL的参数,参见配置项一览表中的"对应URL参数"列。
URL格式:
dubbo://192.168.21.58:20130/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=bbs-service&dubbo=2.5.3&interface=com.alibaba.dubbo.demo.DemoService&methods=getSimpleMemberByUids,getMasterMemberInfo,getUidsByWcuids,getUserInfoListByWcuids,getForumModeratorByUidAndFid,getMemberInfoByUsernames,clearMemberCache,getMemberCountByUids,addDav,updateBio,updateMemberCount,getLastTidsByUids,batchGetMemberProfileModel,getWcuidsByUids,isDav,getUidByWcuid,updateLastTid,saveName,getMemberDetailModelListByUids,register&pid=4481&revision=0.0.1&side=provider&threadpool=cached&threads=200×tamp=1490614869341
服务提供方暴露服务的初始化链,时序图如下:
1、Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。
2、Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
3、Invocation是会话域,它持有调用过程中的变量,比如方法名,参数等。
服务提供者暴露一个服务的详细过程
上图是服务提供者暴露服务的主过程:
首先ServiceConfig类拿到对外提供服务的实际类ref(如:HelloWorldImpl),然后通过ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转化。接下来就是Invoker转换到Exporter的过程。
Dubbo处理服务暴露的关键就在Invoker转换到Exporter的过程(如上图中的红色部分),下面我们以Dubbo和RMI这两种典型协议的实现来进行说明:
1、Dubbo的实现 Dubbo协议的Invoker转为Exporter发生在DubboProtocol类的export方法,它主要是打开socket侦听服务,并接收客户端发来的各种请求,通讯细节由Dubbo自己实现。
2、RMI的实现 RMI协议的Invoker转为Exporter发生在RmiProtocol类的export方法, 它通过Spring或Dubbo或JDK来实现RMI服务,通讯细节这一块由JDK底层来实现,这就省了不少工作量。
代码调用细节:
- public class ServiceBean extends ServiceConfig implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
}
入口在afterPropertiesSet()方法,从spring容器中查找这些bean(ProviderConfig、ApplicationConfig、ModuleConfig、List<RegistryConfig>、MonitorConfig、 List<ProtocolConfig>、),并set到ServiceBean
- com.alibaba.dubbo.config.ServiceConfig.export()。支持延时暴露服务(启动了一个Thread来实现)
- com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory.getInvoker(T, Class, URL),生成AbstractProxyInvoker代理类
- com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol.export(Invoker),生成一个 Exporter实例。这样当网络通讯层收到一个请求后,会找到对应的Exporter实例,并调用它所对应的AbstractProxyInvoker实例,从而真正调用了服务提供者的代码。
服务消费方引用服务的初始化链,时序图如下:
服务消费者消费一个服务的详细过程
首先ReferenceConfig类的init方法调用Protocol的refer方法生成Invoker实例(如上图中的红色部分),这是服务消费的关键,Invoker实现了真正的远程服务调用。接下来把Invoker转换为客户端需要的接口(如:HelloWorld)。
由于Invoker是Dubbo领域模型中非常重要的一个概念,很多设计思路都是向它靠拢。这就使得Invoker渗透在整个实现代码里,对于刚开始接触Dubbo的人,确实容易给搞混了。 下面我们用一个精简的图来说明最重要的两种Invoker:服务提供Invoker和服务消费Invoker:
位于【dubbo-cluster】模块
- com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance:随机(默认方式)
- com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance:轮询
- com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance:最少连接数
- com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance:一致性hash
核心思想:
protected Invoker doSelect(List<Invoker> invokers, URL url, Invocation invocation);从invokers列表中,根据算法选择一个合适Invoker来执行具体业务。
com.alibaba.dubbo.registry.RegistryService:注册服务。提供以下方法:
- void register(URL url);注册数据,比如:提供者地址,消费者地址,路由规则,覆盖规则,等数据。
- void unregister(URL url);取消注册
- void subscribe(URL url, NotifyListener listener);订阅符合条件的已注册数据,当有注册数据变更时自动推送
- void unsubscribe(URL url, NotifyListener listener);取消订阅
- List lookup(URL url);查询符合条件的已注册数据,与订阅的推模式相对应,这里为拉模式,只返回一次结果
实现子类:
- com.alibaba.dubbo.registry.redis.RedisRegistry,负责维护redis缓存存储的注册中心数据
- com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry,负责维护zk存储的注册中心数据
- 提供了注册、取消注册、订阅等一系列功能的具体实现
- ZookeeperRegistry.toUrlPath(URL),通过“/”拼接的路径节点,与zk的树型结构非常匹配,每个接口服务下分别提供了providers和consumers两个中间节点,存储服务节点和消费节点的配置信息。
com.alibaba.dubbo.registry.NotifyListener。当收到服务变更通知时触发
通知需处理契约:
1. 总是以服务接口和数据类型为维度全量通知,即不会通知一个服务的同类型的部分数据,用户不需要对比上一次通知结果。
2. 订阅时的第一次通知,必须是一个服务的所有类型数据的全量通知。<br>
3. 中途变更时,允许不同类型的数据分开通知,比如:providers, consumers, routers, overrides,允许只通知其中一种类型,但该类型的数据必须是全量的,不是增量的。<br>
4. 如果一种类型的数据为空,需通知一个empty协议并带category参数的标识性URL数据。<br>
5. 通知者(即注册中心实现)需保证通知的顺序,比如:单线程推送,队列串行化,带版本对比。<br>
com.alibaba.dubbo.monitor.simple.RegistryContainer,取到RegistryService,实现subscribe节点数据变更方法。
负责客户端与服务端、客户端与注册中心、服务端与注册中心等服务器间的数据通信。底层接口:
com.alibaba.dubbo.remoting.Transporter
com.alibaba.dubbo.remoting.Server
com.alibaba.dubbo.remoting.Client
支持多种通信框架:
- com.alibaba.dubbo.remoting.transport.transporter.netty.NettyTransporter
- com.alibaba.dubbo.remoting.transport.transporter.mina.MinaTransporter
- com.alibaba.dubbo.remoting.transport.transporter.grizzly.GrizzlyTransporter
https://github.com/alibaba/dubbo/wiki/user-guide-sample#%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1