Dubbo基础
1.Dubbo层级结构
- 1.service层:接口层,给服务提供者和消费者来实现的;
- 2.config层:配置层,主要是对dubbo进行各种配置;
- 3.proxy层:服务代理层,无论是consumer还是provider,dubbo都会生成代理,代理之间进行网络通信;
- 4.registry层:服务注册层,服务的注册与发现;
- 5.cluster层:集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务;
- 6.monitor层:监控层,对RPC接口的调用次数和调用时间进行监控;
- 7.protocol层:协议层,远程调用,封装RPC调用;
- 8.exchange层:信息交换层,封装请求响应模式,同步转异步;
- 9.transport层:网络传输层,抽象mina和netty为统一接口;
- 10.serialize层:数据序列化层。
2.工作流程
- provider向注册中心去注册;
- consumer从注册中心订阅服务,注册中心会通知consumer注册好的服务;
- consumer调用provider;
- consumer和provider都异步通知监控中心。
3.通信协议
dubbo支持的通信协议有:dubbo协议(默认),rmi协议,hession协议,http协议,webservice协议。
-
dubbo协议
单一长连接,进行NIO通信,基于hession作为序列化协议。使用场景是传出量小(每次请求在100kb以内),但是并发量很高。
- 长连接就是建立连接之后可以持续发送请求,无须再建立连接;
- 短连接则是每次发送请求之前,都需要先重新建立一次连接。
-
rmi协议
多个短连接,java二进制序列化,适合消费者和提供者数量差不多的情况,适用于文件传输,较少用。
-
hession协议
-
多个短连接,hession序列化协议,适用于提供者数量比消费者数量还多的情况,适用于文件传输,较少用。
-
http协议
json序列化协议。
http协议是应用层的协议,基于请求/响应模式,只要服务端给了响应,本次http请求就结束了,没有长连接和短连接的区别。
http基于传输层的tcp实现,tcp是有长连接和短连接的区别,默认为长连接。
-
webservice协议
SOAP(Simple Object Access Protocol 简单对象访问协议)文本序列化。
4.序列化协议
dubbo支持的序列化协议有:hession(默认),Java二进制,json,SOAP文本序列化。
-
hession序列化
8种原始类型:
-
原始二进制数据
- boolean
- 64-bit date(64位毫秒值的日期)
- 64-bit double
- 32-bit int
- 64-bit long
- null
- string(UTF-8编码)
3种递归类型:
- list for lists and arrays
- map for maps and dictionaries
- object for objects
1种特殊类型:
- ref:表示对共享对象的引用
-
-
Protocol Buffers序列化(dubbo不支持)
Google开源的RPC框架gRPC,基于PB序列化协议,性能很高。
- 使用proto编译器,自动序列化和反序列化,速度非常快;
- 压缩效果好,序列化之后的数据量体积小,因此传输的速度更快。
5.集群容错策略
-
failover(默认)
失败自动切换,自动重试其他服务器,用于读操作;
-
failfast
调用失败立即抛出异常,用于写操作;
-
failsafe
出现异常时忽略掉,常用于不重要的接口调用,比如记录日志;
-
failback
失败了后台自动记录请求,然后定时重发,比较适合写消息队列;
-
forking
并行调用多个provider,只要一个成功就立即返回;
-
broadcast
逐个调用所有的provider。
6.负载均衡策略
- random(默认):随机策略;
- roudRobin:轮询策略,按权重设置轮询比率;
- leastActive:最少活跃调用数;
- consistentHash:一致性hash,保证相同参数的请求总是发送到同一个提供者,当这台服务挂了后,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者。
7.动态代理策略
dubbo默认使用javassist动态字节码生成,创建代理类。可以通过SPI扩展机制配置自己的动态代理策略。
扩展内容:
Spring框架中使用JDK反射和CGLIB包动态生成字节码,来实现动态代理。
javassist和cglib基本属于同一级别的API接口,javassist底层使用BCEL,cglib底层使用ASM。
8.SPI思想(Service Provider Interface,服务提供者接口)
系统中不同模块之间的通信一般是通过接口进行通信的,接口都有多个实现类,如果在模块里编码的时候涉及到了具体的实现类,则后续需要修改实现类或修改原来的模块编码,不利于代码维护。SPI实现了为接口自动寻找实现类的功能。
比如JDBC,java并没有提供JDBC的实现类,实际使用时,根据自己使用的数据库,再具体的引用。
-
JDK中的SPI:主要通过
ServiceLoader
接口来实现具体类的加载;Java SPI具体约定:当服务的提供者,提供了服务接口的一种实现之后,在jar包的
META-INF/services
目录里同时创建一个以服务接口命令的文件,该文件就是实现服务接口的具体实现类。当外部程序装配这个模块时,就能通过该jar包META-INF/services
目录里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 -
Dubbo中的SPI:主要通过
ExtensionLoader
类来实现。Dubbo中的具体类定义在
META-INF/dubbo/internal
目录下。JDK的SPI会在一次实例化所有实现,比较耗时,而且有些可能用不到的实现类也会实例化,浪费资源,所有Dubbo重写一套SPI的规范。