Dubbo 源文件主要包含以上这么多包,其中:java
首先对dubbo-2.8.4.jar 源码的一个截图spring
公共逻辑模块,包括 Util 类和通用模型。网络
远程通信模块,至关于 Dubbo 协议的实现,若是 RPC 用 RMI 协议 则不须要使用此包。并发
Dubbo缺省协议采用单一长链接和NIO异步通信,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的状况。app
链接个数:单链接
链接方式:长链接
传输协议:TCP
传输方式:NIO异步传输
序列化:Hessian二进制序列化
适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者没法压满提供者,尽可能不要用dubbo协议传输大文件或超大字符串。
适用场景:常规远程服务方法调用负载均衡
一、为何要消费者比提供者个数多
因dubbo协议采用单一长链接,
假设网络为千兆网卡(1024Mbit=128MBytae),
根据测试经验数据每条链接最多只能压满7MByte(不一样的环境可能不同,供参考),
理论上1个服务提供者须要20个服务消费者才能压满网卡。异步
二、为何不能传大包
因dubbo协议采用单一长链接,若是每次请求的数据包大小为500KByte,假设网络为千兆网卡(1024Mbit=128MByte),每条链接最大7MByte(不一样的环境可能不同,供参考),
单个服务提供者的TPS(每秒处理事务数)最大为:128MByte / 500KByte = 262。
单个消费者调用单个服务提供者的TPS(每秒处理事务数)最大为:7MByte / 500KByte = 14。
若是能接受,能够考虑使用,不然网络将成为瓶颈。ide
为何采用异步单一长链接:
由于服务的现状大都是服务提供者少,一般只有几台机器, 而服务的消费者多,可能整个网站都在访问该服务,
好比Morgan的提供者只有6台提供者,却有上百台消费者,天天有1.5亿次调用, 若是采用常规的hessian服务,服务提供者很容易就被压跨, 经过单一链接,保证单一消费者不会压死提供者,长链接,减小链接握手验证等,
并使用异步IO,复用线程池,防止C10K问题。函数
约束:测试
参数及返回值需实现Serializable接口
参数及返回值需有无参构造函数(能够是private的)或者有参构造全部函数容许传入null值。
参数及返回值不能自定义实现List, Map, Number, Date, Calendar等接口,只能用JDK自带的实现,由于hessian会作特殊处理,自定义实现类中的属性值都会丢失。
Hessian序列化,只传成员属性值和值的类型,不传方法或静态变量,兼容状况:
数据通信 状况 结果
A->B 类A多一种 属性(或者说类B少一种 属性) 不抛异常,A多的那 个属性的值,B没有, 其余正常
A->B 枚举A多一种 枚举(或者说B少一种 枚举),A使用多 出来的枚举进行传输 抛异常
A->B 枚举A多一种 枚举(或者说B少一种 枚举),A不使用 多出来的枚举进行传输 不抛异常,B正常接 收数据
A->B A和B的属性 名相同,但类型不相同 抛异常
A->B serialId 不相同 正常传输
远程调用模块,抽象各类协议,以及动态代理,只包含一对一的调用, 不关心集群的管理。
集群模块,将多个服务提供方假装为一个提供方,包括:负载均衡, 容 错,路由等,集群的地址列表能够是静态配置的,也能够是由注册中心下发。
监控模块,统计服务调用次数,调用时间的,调用链跟踪的服务。
容器模块,是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,由于服务一般不须要 Tomcat/JBoss 等 Web 容器的特性,不必用 Web 容器去加 载服务。
服务容器只是一个简单的Main方法,并加载一个简单的Spring容器,用于暴露服务。
服务容器的加载内容能够扩展,内置了spring, jetty, log4j等加载,可经过Container扩展点进行扩展
Container 包含:Spring Container Jetty Container Log4j Container
简单介绍一下Spring Container的使用
1)自动加载META-INF/spring目录下的全部Spring配置。
或者 2)配置:(配在java命令-D参数或者dubbo.properties中)
dubbo.spring.config=classpath*:META-INF/spring/*.xml ----配置spring配置加载位置
默认缺省加载Spring Container 缘由:
在dubbo-2.8.4.jar中 在META-INT/dubbo/internal/com.alibba.dubbo.container.Container
spring=com.alibaba.dubbo.container.spring.SpringContainer 有此配置!!!
代码:
/**
* 主线程启动
*/
public class TestMain {
public static void main(String[] args) throws Exception {
com.alibaba.dubbo.container.Main.main(args);
}
}
注册中心模块,基于注册中心下发地址的集群方式,以及对各类注 册中心的抽象。
对于服务提供方,它须要发布服务,并且因为应用系统的复杂性,服务的数量、类型也不断膨胀;对于服务消费方,它最关心如何获取到它所须要的服务,而面对复杂的应用系统,须要管理大量的服务调用。并且,对于服务提供方和服务消费方来讲,他们还有可能兼具这两种角色,即既须要提供服务,有须要消费服务。
经过将服务统一管理起来,能够有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心能够经过特定协议来完成服务对外的统一。Dubbo提供的注册中心有以下几种类型可供选择:
服务首先暴露在服务端,而后调用Registry的register方法在注册中心(它是一个服务协调中心,dubbo之外的独立服务端,dubbo提供了客户端实现)注册服务,而后用户经过配置文件中配置的service的url去subscribe(订阅服务),Registry接收到订阅消息后会往url对应的的List<NotifyListener>中塞入当前NotifyListener,反之从这个list中移除listener就是取消订阅。registry会调用据consumer的订阅状况调用notify方法推送服务列表给Consumer。
Provider初始化时会调用doRegister方法向注册中心发起注册。那么客户端又是怎么subscribe在注册中心订阅服务的呢?答案是服务消费者在初始化ConsumerConfig时会调用RegistryProtocol的refer方法进一步调用RegistryDirectory的subscribe方法最终调用ZookeeperRegistry的subscribe方法向注册中心订阅服务。
注意:
看以下配置发布服务:
<dubbo:registry protocol=”dubbo” address="127.0.0.1:9090" />
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService" protocol=”dubbo” />
1. 指定了哪一种的注册中心,是基于dubbo协议的,指定了注册中心的地址以及端口号
2. 发布DemoService服务,服务的实现为DemoServiceImpl
每一个<dubbo:service/>在spring内部都会生成一个ServiceBean实例,ServiceBean的实例化过程当中调用export方法来暴露服务
1. 经过loadRegistries获取注册中心registryUrls
registry://127.0.0.1:9090/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT&owner=william&pid=7084®istry=dubbo×tamp=1415711791506
用统一数据模型URL表示:
protocol=registry表示一个注册中心url
注册中心地址127.0.0.1:9090
调用注册中心的服务RegistryService
注册中心协议是registry=dubbo
2. 构建发布服务的URL
dubbo://192.168.0.102:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=7084&side=provider×tamp=1415712331601
发布协议protocol =dubbo
服务提供者的地址为192.168.0.102:20880
发布的服务为com.alibaba.dubbo.demo.DemoService
3. 遍历registryUrls向注册中心注册服务
给每一个registryUrl添加属性key为export,value为上面的发布服务url获得以下registryUrl
registry://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT& export=dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.5.4-SNAPSHOT%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26loadbalance%3Droundrobin%26methods%3DsayHello%26owner%3Dwilliam%26pid%3D7084%26side%3Dprovider%26timestamp%3D1415712331601&owner=william&pid=7084®istry=dubbo×tamp=1415711791506
4. 由发布的服务实例,服务接口以及registryUrl为参数,经过代理工厂proxyFactory获取Invoker对象,Invoker对象是dubbo的核心模型,其余对象都向它靠拢或者转换成它。
5. 经过Protocol对象暴露服务protocol.export(invoker)
经过DubboProtocol暴露服务的监听(不是此节内容)
经过RegistryProtocol将服务地址发布到注册中心,并订阅此服务
RegistryProtocol.export(Invoker)暴露服务
< dubbo:registry protocol = ”dubbo” address = "127.0.0.1:9098" />
< dubbo:reference id = "demoService" interface = "com.alibaba.d ubbo.demo.DemoService" />
1. 指定了哪一种的注册中心,是基于dubbo协议的,指定了注册中心的地址以及端口号
2. 引用远程DemoService服务
每一个<dubbo:reference/>标签spring加载的时候都会生成一个Referenc eBean。
如上图ReferenceBean实现了spring的FactoryBean接口, 实现了此接口的Bean经过spring的BeanFactory.getBean(“beanName”)获取的对象不是配置的bean自己而是经过FactoryBean.getObject()方法返回的对象,此接口在spring内部被普遍使用,用来获取代理对象等等。这里getObjec t方法用来生成对远程服务调用的代理
1. loadRegistries()获取配置的注册中心的registryUrls
2. 遍历registryUrls集合,给registryUrl加上refer key就是要引用的远程服务
[ registry ://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.0&pid=2484& refer =application%3Ddemo-consumer%26dubbo%3D2.0.0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D2484%26side%3Dconsumer%26timestamp%3D1415879965901®istry=dubbo×tamp=1415879990670]
3. 遍历registryUrls集合,使用Protocol.refer(interface,regist ryUrl)的到可执行对象invoker
4. 若是注册中心有多个的话, 经过集群策略Cluser.join()将多个invoke r假装成一个可执行invoker, 这里默认使用available策略
5. 利用代理工厂生成代理对象proxyFactory.getProxy(invoker)
以上标签
未完待续.........