服务分层
- Service
业务层,提供接口
- Config
配置层,管理 Dubbo 的配置,由 ServiceConfig 与 ReferenceConfig 两个实现类进行配置
- Proxy
服务代理层,服务的远程调用,都会通过生成代理对象
- Registry
注册层,负责 Dubbo 服务的注册与发现,动态感知服务的注册与销毁
- Cluster
集群容错层,主要包含调用失败时的容错策略、选择具体节点的负载均衡策略、特殊调用路径的路由策略
- 容错策略:Cluster
FailoverCluster:失败转移,默认
FailfastCluster:快速失败,只发起一次调用,通常用于非幂等操作
FailbackCluster:失败后记录下来,后续定时任务重试
BroadcastCluster:广播调用,遍历所有的 Invokers,catch 发生的异常,不影响其它 Invoker 调用
AvailableCluster:获取可用的调用,遍历 Invokers 中 Invoker.isAvalible 方法,为 ture 时直接返回
FailsafeCluster:失败安全,忽略出现的异常
ForkingCluster:并行调用,只要一个成功即返回,通常用于实时性较高的操作,但会浪费更多的服务资源
MergeableCluster:分组聚合,按组合并返回结果,调用者将实现的结果进行合并
- 负载均衡策略:LoadBlance
RandomLoadBalance:随机,默认策略
RoundRobinLoadBalance:权重轮询
LeastActiveLoadBalance:对接口调用前后计数,耗时长比较慢的机器收到更少的请求
ConsistentHashLoadBalance:一致性 Hash ,相同参数请求发送到同一个提供者
特殊调用路径的路由策略:限定消费者只调用某个 IP 的生产者
- Monitor
监控层,负责监控统计服务调用次数和调用时间
- Protocol
远程调用层,封装 RPC 调用具体过程,负责管理 Invoker 的整个生命周期。
Invoker 时 Dubbo 的核心模型,代表一个可执行体
- Exchange
信息交换层,将所有的请求都转换为 Request - Response 模式,封装请求响应请求。
- Transport
网络传输层,抽象网络传输实现,默认 Netty
- 基于 Codec2 数据编码和解码
- 基于 Transport 数据传输封装
- Serialize
序列化层,将数据序列化为二进制流,发送到网络中
Dubbo SPI 机制
区别与联系
Java SPI
Dubbo SPI
Dubbo 中的注解
@SPI
定义接口的实现类
@Adaptive
一般注解在方法上面,代表自动生成和编译一个动态的 Adaptive 类
调用流程
- 1.Proxy持有一个Invoker对象,使用Invoker调用
- 2.之后通过Cluster进行负载容错,失败重试
- 3.调用Directory获取远程服务的Invoker列表
- 4.负载均衡
- 用户配置了路由规则,则根据路由规则过滤获取到的Invoker列表
- 用户没有配置路由规则或配置路由后还有很多节点,则使用LoadBalance方法做负载均衡,选用一个可以调用的Invoker
- 5.经过一个一个过滤器链,通常是处理上下文、限流、计数等。
- 6.会使用Client做数据传输
- 7.私有化协议的构造(Codec)
- 8.进行序列化
- 9.服务端收到这个Request请求,将其分配到ThreadPool中进行处理
- 10.Server来处理这些Request
- 11.根据请求查找对应的Exporter
- 12.之后经过一个服务提供者端的过滤器链
- 13.然后找到接口实现并真正的调用,将请求结果返回
Dubbo 支持的协议
- 1.dubbo 单一长连接和 NIO 异步通讯,适合大并发小数据量的服务调用,以及消费者远大于提供者。传输协议 TCP,异步,Hessian 序列化
- 2.rmi 采用 JDK 标准的 rmi 协议实现,传输参数和返回参数对象需要实现Serializable 接口,使用 java 标准序列化机制,使用阻塞式短连接,传输数据包大小混合,消费者和提供者个数差不多,可传文件,传输协议 TCP。多个短连接,TCP 协议传输,同步传输,适用常规的远程服务调用和 rmi 互 操作。在依赖低版本的 Common-Collections 包,java 序列化存在安全漏洞
- 3.webservice 基于 WebService 的远程调用协议,集成 CXF 实现,提供和原生 WebService 的互操作。多个短连接,基于 HTTP 传输,同步传输,适用系统集成和跨语言调用;
- 4.http 基于 Http 表单提交的远程调用协议,使用 Spring 的 HttpInvoke 实 现。多个短连接,传输协议 HTTP,传入参数大小混合,提供者个数多于消 费者,需要给应用程序和浏览器 JS 调用
- 5.hessian 集成 Hessian 服务,基于 HTTP 通讯,采用 Servlet 暴露服务,Dubbo 内嵌 Jetty 作为服务器时默认实现,提供与 Hession 服务互操作。多个短连接,同步 HTTP 传输,Hessian 序列化,传入参数较大,提供者大于消费者,提供者压力较大,可传文件;
- 6.memcache 基于 memcached 实现的 RPC 协议
- 7.redis 基于 redis 实现的 RPC 协议
设计模式
责任链模式:
责任链模式在Dubbo中发挥的作用举足轻重,就像是Dubbo框架的骨架。Dubbo的调用链组织是用责任链模式串连起来的。
责任链中的每个节点实现Filter接口,然后由ProtocolFilterWrapper,将所有Filter串连起来。
Dubbo的许多功能都是通过Filter扩展实现的,比如监控、日志、缓存、安全、telnet以及RPC本身都是。
观察者模式:
Dubbo中使用观察者模式最典型的例子是RegistryService。消费者在初始化的时候回调用subscribe方法,注册一个观察者,如果观察者引用的服务地址列表发生改变,就会通过NotifyListener通知消费者。
此外,Dubbo的InvokerListener、ExporterListener 也实现了观察者模式,只要实现该接口,并注册,就可以接收到consumer端调用refer和provider端调用export的通知。
修饰器模式:
Dubbo中还大量用到了修饰器模式。比如ProtocolFilterWrapper类是对Protocol类的修饰。在export和refer方法中,配合责任链模式,把Filter组装成责任链,实现对Protocol功能的修饰。
其他还有ProtocolListenerWrapper、 ListenerInvokerWrapper、InvokerWrapper等。
工厂方法模式:
CacheFactory的实现采用的是工厂方法模式。CacheFactory接口定义getCache方法,然后定义一个AbstractCacheFactory抽象类实现CacheFactory,并将实际创建cache的createCache方法分离出来,并设置为抽象方法。这样具体cache的创建工作就留给具体的子类去完成。
抽象工厂模式:
ProxyFactory及其子类是Dubbo中使用抽象工厂模式的典型例子。ProxyFactory提供两个方法,分别用来生产Proxy和Invoker(这两个方法签名看起来有些矛盾,因为getProxy方法需要传入一个Invoker对象,而getInvoker方法需要传入一个Proxy对象,看起来会形成循环依赖,但其实两个方式使用的场景不一样)。
AbstractProxyFactory 实现了 ProxyFactory 接口,作为具体实现类的抽象父类。然后定义了JdkProxyFactory 和 JavassistProxyFactory 两个具体类,分别用来生产基于jdk代理机制和基于javassist代理机制的Proxy和Invoker。
适配器模式:
为了让用户根据自己的需求选择日志组件,Dubbo 自定义了自己的 Logger 接口,并为常见的日志组件(包括jcl, jdk, log4j, slf4j)提供相应的适配器。并且利用简单工厂模式提供一个 LoggerFactory,客户可以创建抽象的 Dubbo 自定义Logger,而无需关心实际使用的日志组件类型。
在 LoggerFactory 初始化时,客户通过设置系统变量的方式选择自己所用的日志组件,这样提供了很大的灵活性。
代理模式:
Dubbo consumer使用Proxy类创建远程服务的本地代理,本地代理实现和远程服务一样的接口,并且屏蔽了网络通信的细节,使得用户在使用本地代理的时候,感觉和使用本地服务一样。
Protocol
第三章 Dubbo 注册中心
种类
流程
Zookeeper
节点类型:
树形结构:
服务发布:创建目录
订阅:
第4章 Dubbo扩展点加载机制
加载机制:SPI,策略模式
扩展点特性:自动包装、自动加载、自适应 @Adaptive,自动激活 @Activate
扩展点注解:
@SPI,标记接口时一个 Dubbo SPI 接口
@Adaptive,@Adaptive注解可以标记在类、接口、枚举类和方法上,但是在整个Dubbo框架中,只有
几个地方使用在类级别上,如AdaptiveExtensionFactory和AdaptiveCompiler,其余都标注在
方法上。
第5章 Dubbo启停原理解析
第7章 Dubbo集群容错
第8章 Dubbo扩展点
Proxy
Dubbo中的
ProxyFactory有两种默认实现:Javassist和JDK,用户可以自行扩展自己的实现,如CGLIB(Code
Generation Library)o Dubbo选用Javassist作为默认字节码生成工具,主要是基于性能和使用的
简易性考虑,Javassist的字节码生成效率相对于其他库更快,使用也更简单
Registry
Cluster
负责了整个Dubbo框架的集群容错,涉及的扩展点较多,包括
- 容错(Cluster)、
- 路由(Router) 现有的路由规则支持文件、脚本和自定义表达式等方式
- 负载均衡(LoadBalance)>内置随机(Random)、 轮询(RoundRobin)、最小连接数(LeastActive)、一致性 Hash (ConsistentHash)这几种负载均 衡的方式,默认使用随机负载均衡策略
- 配置管理工厂(ConfiguratorFactory)
- 合并器(Merger),对并行调用的结果集进行合并
Remote处于整个Dubbo框架的底层,涉及协议、数据的交换、网络的传输、序列化、线程
池等,涵盖了一个远程调用的所有要素。
Protocol 层
Protocol
Filter
在Invoker调用前后执行自定义的逻辑
ExporterListener
ExporterListener和InvokerListener这两个扩展点非常相似,ExporterListener是在暴露和取消
暴露服务时提供回调;InvokerListener则是在服务的引用与销毁引用时提供回调
InvokerListener
Exchanger 层
Exchange层只有一个扩展点接口 Exchanger,这个接口主要是为了封装请求/响应模式,例
如:把同步请求转化为异步请求
既然已经有了 Transport层来传输数据了,为什么还要有Exchange层呢?因为上层业务关
注的并不是诸如Netty这样的底层Channel。上层一个Request只关注对应的Response,对于是
同步还是异步请求,或者使用什么传输根本不关心。Transport层是无法满足这项需求的,
Exchange层因此实现了 Request-Response模型,我们可以理解为基于Transport层做了更高层次的封装
Transport 层
Transporter 屏蔽了通信框架接口、实现的不同,使用统一的通信接口,默认 netty4
Dispatcher,通过不同的派发策略,把工作派发到不同的线程池,以此来应 对不同的业务场景
Codec2 主要实现对数据的编码和解码,但这个接口只是需要实现编码/解码过程中的通用逻
辑流程,如解决半包、粘包等问题。该接口属于在序列化上封装的一层
ChannelHandler 主要处理连接相关的事件,例如:连接上、断开、发送消息、收到消息、出现异常等
Serialization 层
第9章 Dubbo 高级特性
隐式参数
第10章 Dubbo过滤器
第11章 Dubbo注册中心扩展 实践
etcd使用了 Raft算法保证集群中数据的一致性,当leader节点下
线时会自动触发新的leader选举,以此容忍机器的故障
相比于ZooKeeper实现,基于etcd实现的注册中心有很多优点,例如:不需要每次子节
点变更都重新全量拉取节点数据,大大降低了网络的压力。