按照完整的Dubbo结构分层,RPC层可以分为四层:Config、Proxy、Registry、Cluster。由于Config属于API范畴,因此只关注Proxy、Registry、Cluster三层的扩展点。
Proxy层主要的扩展接口是ProxyFactory
。Dubbo中的ProxyFactory有两种默认实现:Javassist和JDK
,用户可以自行扩展自己的实现,如CGLIB。Dubbo默认选择Javassist作为默认字节码生成工具,主要是基于性能和使用的简易性考虑,Javassist的字节码生成效率相对于其他库更快。
ProxyFactory接口有两个方法,每个方法上都有@Adaptive注解,并且方法会根据URL中的proxy参数决定使用哪种字节码工具。
已有的扩展点实现:
扩展key名 | 扩展类名 |
---|---|
jdk | org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory |
javassist | org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory |
Registry层可以理解为注册层,这一层中最重要的扩展点就是org.apache.dubbo.registry.RegistryFactory
。整个框架的注册与服务发现客户端都是由这个扩展点负责创建的。该座站点有@Adaptive({"protocol"})
注解,可以根据URL中的protocol参数创建不同的注册中心客户端。
例如:protocol=redis
,该工厂会创建基于Redis的注册中心客户端。因此,如果我么扩展了自定义的注册中心,那么只需要配置不同的Protocol即可。
使用这个扩展点,还一些需要遵循的"潜规则":
check=false
,则连接不会被检查。否则,需要在断开连接时抛出异常;username:password
格式在URL中传递鉴权;在Dubbo,有AbstractRegistryFactory已经抽象了一些通用的逻辑,用户可以直接继承该抽象类实现自定义的注册中心工厂。
已有的RegistryFactory实现:
扩展key名 | 扩展类名 |
---|---|
zookeeper | org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory |
redis | org.apache.dubbo.registry.redis.RedisRegistryFactory |
multicast | org.apache.dubbo.registry.multicast.MulticastRegistryFactory |
dubbo | org.apache.dubbo.registry.multicast.MulticastRegistryFactory |
Cluster层负责了整个Dubbo框架的集群容错,涉及的扩展点较多,包括容错(Cluster)、路由(Router)、负载均衡(LoadBalnce)、配置管理工厂(ConfiguratorFactory)和合并器(Merger)。
1.3.1 Cluster扩展点:
Cluster需要与Cluster层区分开,Cluster主要负责一些容错的策略,也是整个集群容错的入口。当远程调用失败后,由Cluster负责重试、快速失败等,整个过程对上层透明。
Cluster接口只有一个join方法,并且有@Adaptice
注解,说明会根据配置动态调用不同的容错机制。
扩展key名 | 扩展类名 |
---|---|
mock | org.apache.dubb.rpc.cluster.support.wrapper.MockClusterWrapper |
failover | org.apache.dubb.rpc.cluster.support.FailoverCluster |
failfast | org.apache.dubb.rpc.cluster.support.FailfastCluster |
failsafe | org.apache.dubb.rpc.cluster.support.FailsafeCluster |
failback | org.apache.dubb.rpc.cluster.support.FailbackCluster |
forking | org.apache.dubb.rpc.cluster.support.ForkingCluster |
available | org.apache.dubb.rpc.cluster.support.AvailableCluster |
mergeable | org.apache.dubb.rpc.cluster.support.MergeableCluster |
broadcast | org.apache.dubb.rpc.cluster.support.BroadcastCluster |
registryware | org.apache.dubb.rpc.cluster.support.RegistryAwareCluster |
1.3.2 RouterFactory扩展点:
RouterFactory是一个工厂类,就是用于创建不同的Router。假设接口A有多个服务提供者提供服务,如果配置了路由规则(某个消费者只能调用某几个服务提供者),则Router会过滤其他服务提供者,只留下符合路由规则的服务提供者列表。
现有的路由规则支持文件、脚本和自定义表达式
等方式。接口上有@Adaptive("protocol")
注解,会根据不同的protocol自动匹配路由规则。
在2.7版本之后,路由模块会做出较大的更新,每个服务中每种类型的路由只会存在一个,它们会成为路由器链。
扩展key名 | 扩展类名 |
---|---|
fie | org.apache.dubbo.rpc.cluster.router.file.FileRouterFacttory |
script | org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory |
condition | org.apache.dubbo.rpc.cluster.router.condition.CnditionRouterFactory |
service | org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory |
app | org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory |
tag | org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory |
mock | org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory |
1.3.3 LoadBalance扩展点:
LoadBalance是Dubbo框架中的负载均衡策略扩展点,框架中已经内置随机(Random)、轮询(RoundRobin)、最小连接数(LeastActive)、一致性Hash(ConsistenHash)这几种负载均衡策略,默认使用随机负载均衡。
LoadBalance主要负责在多个节点中,根据不同的负载均衡策略选择一个合适的节点来调用。
扩展key名 | 扩展类名 |
---|---|
random | org.apache.dubbo.rpc.cluster.loadbalane.RandomLoadBalance |
roundrobin | org.apache.dubbo.rpc.cluster.loadbalane.RoundRobinLoadBalance |
leastactive | org.apache.dubbo.rpc.cluster.loadbalane.LeastActiveLoadBalance |
consistenthash | org.apache.dubbo.rpc.cluster.loadbalane.ConsistentHashLoadBalance |
1.3.4 ConfiguratorFactory:
ConfiguratorFactory是创建配置实例的工厂类,现有override和absent两种工厂实现,分别会创建爱你OverrideConfigurator和AbsentConfigurator两种配置对象。默认的两种实现,OverrideConfigurator会直接把配置心中的参数覆盖本地的参数;AbsentConfigurator会先看本地是否存在该配置,没有则新增本地配置,如果已经存在则不会覆盖。
该扩展点的方法也有@Adaptive("protocol")
注解,会根据URL中的protocol配置值使用不同的扩展点实现。
扩展key名 | 扩展类名 |
---|---|
override | org.apache.dubbo.rpc.cluster.configurator.override.OverrideConfiguratorFactory |
sbsent | org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfiguratorFactory |
1.3.5 Merger扩展点:
Merger是合并器,可以对并行调用的结果集进行合并,例如:并行调用A、B两个服务器都会返回一个List结果集,Merger可以把两个List合并为一个并返回给应用。默认已经支持map、set、list、byte等11中类型的返回值。用户可以基于该扩展点,添加自定义类型的合并器。
扩展key名 | 扩展类名 |
---|---|
map | org.apache.dubbo.rpc.cluster.merger.MapMerger |
set | org.apache.dubbo.rpc.cluster.merger.SetMerger |
list | org.apache.dubbo.rpc.cluster.merger.ListMerger |
byte | org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger |
char | org.apache.dubbo.rpc.cluster.merger.CharArrayMerger |
short | org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger |
int | org.apache.dubbo.rpc.cluster.merger.IntArrayMger |
long | org.apache.dubbo.rpc.cluster.merger.LongArrayMerger |
float | org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger |
duouble | org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger |
boolean | org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger} |
Remote处于整个Dubbo框架的底层,设计协议、数据的交换、网络的传输、序列化、线程池等,涵盖了一个远程调用的所有要素。
Remote层是对Dubbo传输协议的封装,内部再划分Transport传输层和Exchange信息叫魂层其中Transport层只负责单向消息传输,是对Mina、Netty等传输工具库的抽象。而Exchange层在传输层之上实现了Request-Response语义,这样就可以在不同传输方式之上都能做到统一的请求/响应处理。Serialize层是RPC的一部分,决定了在消费者和服务提供者之间的二进制数据传输格式。不同的序列化库的选择会对RPC调用的性能产生重要影响,目前默认选择是Hessian2序列化。
Protocol层主要包含四大扩展点,分别是Protocol、Filte、ExporterListener和InvokerListener。
2.1.1 Protocol扩展点:
Protocol是Dubbo RPC的核心调用层,具体的RPC协议都可以由Protocol点扩展。如果想增加一种新的RPC协议,则只需要扩展一个新的Protocol扩展点 即可。
@SPI("dubbo")
public interface Protocol {
//当用户没有设置端口的时候,返回默认的端口
int getDefaultPort();
//把一个服务暴露成远程invocation
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
//易用一个远程服务
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
//销毁
void destroy();
}
Protocol的每个接口都会有一些"显规则",在实现自定义的时候需要注意:
export方法:
RpcContext.getContext().setRemoteAddress()方法存入RPC上下文
refer方法:
check=false
时,自定义的协议实现必须不能抛出异常,而是在出现连接失败异常时尝试恢复连接。destroy方法:
整个Protocol的逻辑由Protocol、Exporter、Invoker三个接口穿起来:
其中Protocol接口是入口,其实现封装了用来处理Exporter和Invoker的方法:
Exporter代表要暴露的远程服务引用, Protocol#export
方法是将服务暴露的处理过程,Invoker代表要调用的远程服务代理对象,Protocol#refer
方法通过服务类型和URL获得要调用的服务代理。
由于Protocol可以实现Invoker和Exporter对象的创建,因此除了作为远程调用对象的构造,还能用于其他用途,例如:可以在创建Invoker的时候对原对象进行包装增强,添加其他File进去,Polorraper实现就是把Fiter链加入Invoker。如果对这一段并不是十分了解则可以先了解设计模式中的装饰器模式,对最原始的Invoker进行增强。
扩展key名 | 扩展类名 |
---|---|
injvm | org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol |
dubbo | org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol |
rmi | org.apache.dubbo.rpc.protocol.rmi.RmProtocol |
http | org.apache.dubbo.rpc.protocol.http.HttpProtocol |
hessian | org.apache.dubbo.rpc.protocol.hessian.HessianProtocol |
rest | org.apache.dubbo.rpc.protocol.rest.RestProtocol |
thrift | org.apache.dubbo.rpc.protocol.ThriftProtocol |
- | org.apache.dubbo.rpc.protocol.webservice.WebServiceProtocol |
redis | org.apache.dubbo.rpc.protocol.redis.RedisProtocol |
memcached | org.apache.dubbo.rpc.protocol.memcached.MemcachedProtocol |
2.1.2 Filter扩展点:
Filter是Dubbo的过滤器扩展点,可以自定义过滤器,在Invoekr调用前后执行自定义的逻辑。在Filter的实现中,必须要调用传入的Invoker的invoke方法,否则整个链路就断了。
2.1.3 ExprterListener / InvokerListener 扩展点:
ExprterListener和InvokerListener这两个扩展点非常相似,ExporterListener是在暴露和取消暴露服务时提供回调;InvokerListener则是在服务的引用于销毁时提供回调。
Echange层只有一个扩展点接口Exchanger,这个接口主要是为了封装请求/响应模式,例如:把同步请求转换为异步请求。默认的扩展点实现是org.apache.dubbo.remoting.exchange.support.header.HeaderExchanger
。每个方法上都有@Adaptive注解,会根据URL中的Exchanger参数决定实现类。
既然已经有了Transport层来传输数据了,为什么还要有Exchange层呢?因为上层业务关注的并不是诸如Netty这样的底层Channel。上层一个Request只关注对应的Response,对于是同步还是异步请求,或者使用什么传输技术根本不关心。Transport层是无法满足这项需求的,Exchange层因此实现了Request-Response模型,可以理解为做了更高层次的封装。
tranport层为了屏蔽不同通信框架的异同,封装了统一的对外接口。主要的扩展点有Transporter、Dispatcher、codec2和ChanelHandler。
其中,Channelhandler主要处理连接相关的时间,例如:连接上、断开、发送消息、收到消息、出现异常等。虽然接口上有SPI注解,但是在框架中实现类的使用却是直接"new"的方式。
2.3.1 Transporter扩展接口:
Transporter屏蔽了通信框架接口、实现的不同,使用同一的通信接口。
bind方法会生成一个服务,监听来自客户端的请求;connect方法则会连接到一个服务。两个方法上都有@Adaptive注解,首先会根据URL中server的参数值去匹配实现类,如果匹配不到则根据transporter参数去匹配实现类。默认的实现是netty4.
扩展key名 | 扩展类名 |
---|---|
mina | org.apache.dubbo.remoting.transport.mina.MinaTransporter |
netty3 | org.apache.dubbo.remoting.transport.netty.NettyTransporter |
netty4 | org.apache.dubbo.remoting.transport.netty4.NettyTransporter |
netty | org.apache.dubbo.remoting.transport.netty4.NettyTransporter |
grizzly | org.apache.dubbo.remoting.transport.grizzly.GrizzlyTransporter |
2.3.2 Dispatcher扩展接口:
如果有些逻辑的处理比较慢,例如:发起I/O请求查询数据库、请求远程数据等,则需要使用线程池。因为I/O速度相对CPU是很慢的,如果不适用线程池,则线程会因为I/O导致同步阻塞等待。Dispatcher扩展接口通过不同的派发策略,把工作派发到不同的线程池,以此来应对不用的业务场景。
扩展key名 | 扩展类名 |
---|---|
all | org.apache.dubbo.remoting.transport.dispatcher.all.AllDispatcher |
direct | org.apache.dubbo.remoting.transport.dispatcher.direct.DirectDispatcher |
message | org.apache.dubbo.remoting.transport.dispatcher.message.MessageOnlyDispatcher |
execution | org.apache.dubbo.remoting.transport.dispatcher.execution.ExecutionDispatch |
connection | org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedDispatcher |
2.3.3 Codec2扩展接口:
Codec2主要实现对数据的编码和解码,但这个接口只是需要实现编码/解码过程中的通用逻辑流程,如解决半包、粘包等问题。该接口属于在序列化上封装的一层。
扩展key名 | 扩展类名 |
---|---|
transport | org.apache.dubbo.remoting.trnsport.codec.TranspotCodec |
telnet | org.apache.dubbo.remoting.elnet.codec.TelnetCodec |
exchange | org.apache.dubbo.remoting.exchange.codec.ExchangeCodec |
2.3.4 TreadPool扩展接口:
Transport层由Dispatcher实现不同的派发策略,最终会派发到不同的ThreadPool中执行。
现阶段,框架中默认含有四种线程池扩展的实现,以下内容摘自官方文档:
其接口的实现类如下:
Serialize层主要实现具体的对象序列化,只有Serialization一个扩展接口。Serialization是具体的对象序列化扩展接口,即把对象序列化成可以通过网络进行传输的二进制流。
2.4.1 Serialization扩展接口:
Serialization默认使用Hessian2做序列化,已有的实现如下表:
扩展key名 | 扩展类名 |
---|---|
fastjson | org.apache.dubbo.common.serialize.fastjson.FastJsonSerialization |
fst | org.apache.dubbo.common.serialize.fst.FstSerialization |
hessian2 | org.apache.dubbo.common.serialize.hessian2.Hessian2Serialization |
java | org.apache.dubbo.common.serialize.java.JavaSerialization |
compactedjava | org.apache.dubbo.common.serialize.java.CompactedJavaSerialization |
nativejava | org.apache.dubbo.common.serialize.nativejava.NativeJavaSerialization |
kryo | org.apache.dubbo.common.serialize.kryo.KryoSerialization |
protostuff | org.apache.dubbo.common.serialize.protostuff.ProtostuffSerialization |
其中compactedjava是在Java原生序列化的基础上做了压缩,实现了自定义的类描写叙述符合写入和读取。在序列化的时候仅写入类名,而不是完整的类信息,这样在对象数量很多的情况下,可以有效压缩体积。
NativeJavaSerialization是Java原生的序列化方式。
JavaSerializaiton是原生Java序列化及压缩的封装。
还有其他额一些扩展点接口:TelnetHandler、StatusChecker、Container、CacheFactory、Validation、LoggerAdapter和Compiler。
3.1 Telnethandler扩展点
Dubbo框架支持Telnet命令连接,TelnetHandler接口就是用于扩展新的Telnet命令的接口。
扩展key名 | 扩展类名 |
---|---|
clear | org.apache.dubbo.remoting.telnet.support.command.ClearTelnetHandler |
exit | org.apache.dubbo.remoting.telnet.support.command.ExitTelnetHandler |
help | org.apache.dubbo.remoting.telnet.support.command.HelpTelnetHandler |
status | org.apache.dubbo.remoting.telnet.support.command.StatusTelnetHandler |
log | org.apache.dubbo.remoting.telnet.support.command.LogTelnetHandler |
3.2 StatusChecker扩展点:
通过这个扩展点,可以让Dubbo框架支持各种状态的检查,默认已经实现了内存和load的检查。用户可以自定义扩展,如硬盘、CPU等的状态检查。
扩展key名 | 扩展类名 |
---|---|
memory | org.apache.dubbo.common.status.support.MemoryStatusChecker |
load | org.apache.dubbo.common.status.support.LoadStatusChecker |
3.3 Container扩展点:
服务容器就是为了不需要使用外部的Tomcat、JBoss等web容器来运行服务,因为有可能服务根本用不到它们的功能,只是简单地Main方法中暴露一个服务即可。此时就可以使用服务容器。Dubbo默认使用Spring作为服务容器。
3.4 CacheFactory扩展点:
可以通过dubbo:method
配置每个方法的调用返回值是否进行缓存,用于加速数据访问速度。
扩展key名 | 扩展类名 |
---|---|
threadlocal | org.apache.dubbo.cache.support.threadlocal.ThreadLocalCacheFactory |
lru | org.apache.dubbo.cache.support.lru.LruCacheFactory |
jcache | org.apache.dubbo.cache.support.jcache.JCacheFactory |
expiring | org.apache.dubbo.cache.support.expiring.ExpiringCacheFactory |
其中:
3.5 Validation扩展点:
该扩展点主要实现参数点校验,我们可以在配置中使用
实现参数的校验。已知的扩展实现有:
扩展key名 | 扩展类名 |
---|---|
jvalidation | org.apache.dubbo.validation.spport.jvalidation.JValidation |
3.6 LoggerAdapter扩展点:
日志适配器主要用于适配各种不同的日志框架,使其有统一的使用接口。已知的扩展点实现如下:
扩展key名 | 扩展类名 |
---|---|
slf4j | org.apache.dbbo.common.logger.slf4j.Slf4jLoggerAdapter |
jcl | org.apache.dbbo.common.logger.jcl.JclLoggerAdapter |
log4j | org.apache.dbbo.common.logger.log4j.Log4jLoggerAdapter |
jdk | org.apache.dbbo.common.logger.jdk.JdkLoggerAdapter |
log4j2 | org.apache.dbbo.common.logger.log4j2.Log4j2LoggAdapter |
3.7 Compiler扩展点:
@Adaptive注解会生成Java代码,然后使用编译器动态编译出新的Class。Compiler接口就是可可扩展的编译器,现有两个uti的实现(adaptive不算在内):
扩展key名 | 扩展类名 |
---|---|
jdk | org.apache.dubbo.common.compiler.suppot.JdkCompiler |
javassist | org.apache.dubbo.common.compiler.suppot.JavassistCompiler |