所有内容,以Dubbo官方的2.7.5 release版本为基础。
Dubbo中的同步调用/异步调用
Dubbo框架中的默认缺省协议:Dubbo协议(DubboProtocol
)采用的是单一长连接,底层默认使用的是Netty的NIO异步通信。这种协议适用于小数据量大并发的服务调用。基于这种机制,Dubbo主要提供了以下几种调用方式:
- one way(客户端发送消息后,不需要接受响应)
- sync(同步,平常用的最多的)
- future(异步回调,future.get()阻塞当前线程)
- callback(异步回调,由回调线程处理,不阻塞当前线程)
可以通过 sent
设置是否等待消息发出:
sent="true"
等待消息发出,消息发送失败将抛出异常。sent="false"
不等待消息发出,将消息放入 IO 队列,即刻返回。
<dubbo:method name="findFoo" async="true" sent="true" />
如果想做到one way这样的形式,奖方法标记为async,return设置为false即可,不会创建 CompletableFuture
对象。
<dubbo:method name="findFoo" async="true" return="false" />
Dubbo中的线程模型(dispatcher)
Dubbo中的线程大体可以分为IO线程和业务线程两类,它们要处理请求,响应,心跳,连接事件,断开事件等消息。Dubbo提供了五种不同的派发策略(dispatcher),我们可以根据自己的实际场景选择不同的派发策略、线程池类型、线程池大小。
all
所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。direct
所有消息都不派发到线程池,全部在 IO 线程上直接执行。message
只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。execution
只有请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。connection
在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
默认使用的派发策略是 all
,线程池是 fixed
,大小为 200
。
官方对派发策略的推荐是:
如果事件处理的逻辑能迅速完成,并且不会发起新的 IO 请求,比如只是在内存中记个标识,则直接在 IO 线程上处理更快,因为减少了线程池调度。
但如果事件处理逻辑较慢,或者需要发起新的 IO 请求,比如需要查询数据库,则必须派发到线程池,否则 IO 线程阻塞,将导致不能接收其它请求。
可以根据不同的业务场景选择不同的策略,也可以自定义扩展 Dispatcher
。
Dubbo中的支持的协议,序列化工具等等
序列化工具
Dubbo默认使用Hessian2作为序列化工具,同时Dubbo还支持FastJson、Java序列化、Protostuff(不用写.proto的protobuff)等等。
可以实现 org.apache.dubbo.common.serialize.Serialization
进行自定义扩展。
调用协议
默认使用Dubbo协议,Dubbo协议使用TCP传输,采用单一长连接+NIO 异步通讯。除此之外,还支持RMI这种阻塞式短连接(远程调用中JDK的标准实现),贡献自DubboX的rest协议。Dubbo还支持gRPC这样高性能的协议以及http普遍通用的远程调用。
可以实现 org.apache.dubbo.rpc.Protocol
进行自定义扩展。
注册中心
推荐使用ZooKeeper作为注册中心,和ZooKeeper类似的etcd也已支持。还支持Multicast这样广播的形式,Nacos、Redis、Consul等等都是支持的。
可以实现 org.apache.dubbo.registry.Registry
进行自定义扩展。
Dubbo2.7.2以后支持了多注册中心。
dubbo支持多注册,多消费 可以将你们的Provider为每个注册中心都注册一份数据,消费方消费多个注册中心服务,目前dubbo是按照配置注册中心的循序进行消费,比如是配置了redis, zk注册中心,优先消费redis服务,如果redis没有服务会自动去消费zk服务
负载均衡策略
-
Random LoadBalance
-
- 随机,按权重设置随机概率。dubbo默认的负责均衡策略。
-
- 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
-
RoundRobin LoadBalance
-
- 轮询,按公约后的权重设置轮询比率。
-
- 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
-
LeastActive LoadBalance
-
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
- 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
-
ConsistentHash LoadBalance
-
- 一致性Hash,相同参数的请求总是发到同一提供者。
- 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
- 缺省只对第一个参数Hash,修改请配置
- 缺省用160 份虚拟节点,修改请配置
集群的容错模式
-
FailOver Cluster
故障转移模式,dubbo默认的集群容错模式。
-
失败自动切换,当出现失败时,重试其他服务器
-
通常用于读操作,但重试会带来更长延迟
-
可通过设置retries=2来设置重试次数(不含第一次)
<dubbo:service retries="2" cluster="failover"/>或<dubbo:reference retries="2" cluster="failover"/>
-
-
FailFast Cluster
快速失败模式,只发起一次调用,失败立即报错
通常用于非幂等性的写操作,比如新增记录。
<dubbo:service cluster="failfast" /> <dubbo:reference cluster="failfast" />
-
FailSafe Cluster
安全失败模式,出现异常,直接忽略。
通常用于写入审计日志等操作。
<dubbo:service cluster="failsafe" /> <dubbo:reference cluster="failsafe" />
-
Failback Cluster
失败后自动恢复,后台记录失败请求,定时重发
通常用于消息通知操作
<dubbo:service cluster="failback" /> <dubbo:reference cluster="failback" />
-
Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源,可通过forks=”2”来设置最大并行数。
<dubbo:service cluster="forking" forks="2"/> <dubbo:reference cluster="forking" forks="2"/>
-
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。
通常用于通知所有提供者更新缓存或日志等本地资源信息。
通信框架
Dubbo默认使用的Netty4作为通信框架,除此之外Dubbo还支持netty3、mina、grizzly。
通信框架主要负责远程传输和通讯,相关扩展接口如下:
org.apache.dubbo.remoting.Transporter
org.apache.dubbo.remoting.Server
org.apache.dubbo.remoting.Client
动态代理策略
Dubbo中默认采用 Javassist
作为动态代理工具,此外还支持 JDK
。为什么选择 Javassit
,Dubbo的开发者【梁飞】在博客 《动态代理方案性能对比》 中说主要是出于性能的考虑。Javassit
提供字节码 bytecode
生成方式和动态代理接口两种方式。Javassit
动态代理接口的方式,效率比JDK自带的还差,所以Dubbo使用的是它的 bytecode
生成方式。
常见的实现动态代理的几种方案:
- jdk 动态代理
- cglib 动态代理
- javassist 动态代理
- ASM 字节码
- javassist 字节码
##Dubbo中的SPI机制
Dubbo中的限流(Sentinel)
1.原生的TpsLimitFilter
2.Sentinel