Dubbo从2.7.0版本开始正式支持配置中心,在服务自省架构中也依赖配置中心完成ServiceID与ServiceName的映射。配置中心在Dubbo中主要承担两个职责:外部化配置:目的之一是实现配置的集中式管理,目前已经有很多成熟的专业配置管理系统(例如,携程开源的Apollo、阿里开源的Nacos等),Dubbo配置中心的目的不是”重复造轮子”,而是保证Dubbo能与这些成熟的配置管理系统一起正常工作;服务治理:负责服务治理规则的存储与通知。Dubbo可以同时支持多种配置来源。在Dubbo初始化过程中,会从多个来源获取配置,并按照固定的优先级将这些配置整合起来,实现高优先级的配置覆盖低优
上一章,我介绍了Dubbo的服务自省架构中的元数据方案,整个服务自省架构除了元数据方案还需要服务发布订阅功能的支持。本章,我就来讲解Dubbo中服务实例的发布与订阅功能的具体实现:首先,我会对ServiceDiscovery接口的核心定义进行讲解;然后,我会重点介绍以ZooKeeper为注册中心的ZookeeperServiceDiscovery实现,这其中还会涉及相关事件监听的实现。一、ServiceDiscoveryServiceDiscovery主要封装了针对ServiceInstance的发布和订阅操作,你可以暂时将其理解成一个ServiceInstance的注册中心。ServiceD
在微服务架构中,服务是基本单位,而Dubbo架构中服务的基本单位是Java接口,这种架构上的差别就会带来一系列挑战。从Dubbo2.7.5版本开始,Dubbo引入了服务自省架构,来应对微服务架构带来的挑战。一、注册中心1.1传统架构我们先来回顾一下Dubbo传统架构中最核心的组件:我们知道URL是贯穿整个Dubbo服务注册与发现的核心。ProviderURL注册到ZooKeeper上的大致格式如下:dubbo://192.168.0.100:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-pro
Dubbo作为一个RPC框架,暴露给用户最基本的功能就是服务发布和服务引用。在上一章,我已经分析了服务发布的核心流程。那么在本章,我就接着深入分析服务引用的核心流程。Dubbo支持两种方式引用远程的服务:服务直连:仅适合在测试场景调试服务时使用;基于注册中心引用:这是生产环境中使用的服务引用方式。一、DubboBootstrap入口在上一章介绍服务发布的时候,我介绍了DubboBootstrap.start()方法的核心流程,其中除了会调用exportServices()方法完成服务发布之外,还会调用referServices()方法完成服务引用。在DubboBootstrap.referSe
在前面的章节中,我已经将整个Dubbo的核心实现进行了分析。接下来的章节,我将串联Dubbo中的这些核心实现,分析Dubbo服务发布和服务引用的全流程,将之前介绍的独立知识点联系起来,形成一个完整整体。本章,我先来介绍Provider节点发布服务的过程,在这个过程中会使用到之前介绍的很多Dubbo核心组件。我将从DubboBootstrap这个入口类开始介绍,分析ProviderURL的组装以及服务发布流程,其中会详细介绍本地发布和远程发布的核心流程。一、服务发布入口1.1DubboBootstrap从前面章节dubbo-demo-api-provider示例的Provider实现中,我们可以
Mock机制是RPC框架中的常见功能,不仅可以用来实现服务降级,还可以用来在测试中模拟调用的各种异常情况。Dubbo中的Mock机制是在Consumer这一端实现的,具体来说就是在Cluster这一层实现的。在前面章节中,我深入介绍了Dubbo提供的多种Cluster实现以及相关的ClusterInvoker实现,其中的ZoneAwareClusterInvoker就涉及了MockClusterInvoker的相关内容。本章,我主要介绍Dubbo中Mock机制的全链路流程,包括与Cluster接口相关的MockClusterWrapper和MockClusterInvoker,我还会回顾前面章
在上一章中,我分析MergeableClusterInvoker的具体实现时,讲解过这样的内容:MergeableClusterInvoker会读取URL中的merger参数值,如果merger参数以"."开头,则表示"."后的内容是一个方法名,这个方法名是远程目标方法的返回类型中的一个方法,MergeableClusterInvoker在拿到所有Invoker返回的结果对象之后,会遍历每个返回结果,并调用merger参数指定的方法,合并这些结果值。其实,除了上述指定Merger方法名称的合并方式之外,Dubbo内部还提供了很多默认的Merger实现,这
上一章,我对DubboCluster层的Cluster容错机制的相关内容进行了讲解,主要介绍了Cluster接口的定义以及其抽象实现类的核心功能。本章,我将对Cluster层各种集群容错策略的具体实现进行分析。一、Failover:失败自动切换FailoverCluster,失败自动切换。Dubbo的默认容错机制,在请求一个Provider节点失败时,自动切换其他Provider节点,默认执行3次,适合幂等操作。当然,重试次数越多,在故障容错的时候带给Provider的压力就越大,在极端情况下甚至可能造成雪崩。1.1FailoverClusterFailoverCluster的doJoin()
本章,我将对DubboCluster层中的Cluster接口进行深入分析。Cluster接口提供了集群容错功能。集群中的单个节点有一定概率出现一些问题,例如,磁盘损坏、系统崩溃等,导致节点无法对外提供服务,因此在分布式RPC框架中,为了避免单点故障,Provider通常至少会部署在两台服务器上,以集群的形式对外提供服务,对于一些负载比较高的服务,则需要部署更多Provider来抗住流量。在Dubbo中,通过Cluster这个接口把一组可供调用的Provider信息组合成为一个统一的Invoker供调用方进行调用。经过Router过滤、LoadBalance选址之后,选中一个具体Provider
在前面的章节中,我已经详细介绍了dubbo-cluster模块中的Directory和Router两个核心接口及实现。本章我继续按照下图的顺序介绍LoadBalance的相关内容。LoadBalance(负载均衡)的职责是将网络请求或者其他形式的负载“均摊”到不同的服务节点上,从而避免服务集群中部分节点压力过大、资源紧张,而另一部分节点比较空闲的情况。通过合理的负载均衡算法,我们希望可以让每个服务节点获取到适合自己处理能力的负载,实现处理能力和流量的合理分配。Dubbo需要对Consumer的调用请求进行分配,避免少数Provider节点负载过大,而剩余的其他Provider节点处于空闲的状态
在前面章节,我讲解了RegistryDirectory相关的内容,作为一个NotifyListener监听器,RegistryDirectory会同时监听注册中心的providers、routers和configurators三个目录。通过RegistryDirectory处理configurators目录的逻辑,我们了解到configurators目录中动态添加的URL会覆盖providers目录下注册的ProviderURL,Dubbo还会按照configurators目录下的最新配置,重新创建Invoker对象(同时会销毁原来的Invoker对象)。在老版本的Dubbo中,我们可以通过服
本章,我将对dubbo-cluster模块中的Router路由机制进行讲解。Router的主要功能就是根据用户配置的路由规则以及请求携带的信息,过滤出符合条件的Invoker集合,供后续负载均衡逻辑使用。在上一章介绍RegistryDirectory的实现时,我们看到了RouterChain这个Router链的存在,但是没有深入分析,下面我就对RouterChain进行分析。一、RouterChain1.1核心字段RouterChain的核心字段如下://RouterChain.javapublicclassRouterChain<T>{//待过滤的Invoker集合private
从本章开始,我将对Dubbo架构中的Cluster层进行分析。在生产环境中,为了保证服务的高可用、高性能以及容错能力,我们通常会在多个服务器上运行相同的服务端程序,然后以集群的形式对外提供服务。根据各项性能指标的要求不同,各个服务端集群中服务实例的个数也不尽相同,从几个实例到几百个实例不等。针对这种服务集群的情况,客户端程序需要解决一些问题,比如:客户端程序是否要感知每个服务端地址?客户端程序的一次请求,到底调用哪个服务端程序呢?请求失败之后是重试,还是抛出异常?如果是重试,是再次请求该服务实例,还是尝试请求其它服务实例?服务端集群如何做到负载均衡,负载均衡的标准是什么呢?为了解决上述问题,D
Filter是扩展Dubbo功能的首选方案,并且Dubbo自身也提供了非常多的Filter实现来扩展自身功能。Filter链的组装逻辑设计得非常灵活,其中可以通过-配置手动剔除Dubbo原生提供的、默认加载的Filter,通过default来代替Dubbo原生提供的Filter,这样就可以很好地控制哪些Filter要加载,以及Filter的真正执行顺序。Filter在Dubbo架构中的位置如下图所示:本章,我就对Dubbo内置的各种Filter的功能和源码实现进行分析,同时讲解自定义扩展Filter的方法。一、内置FilterDubboPRC层提供的各种内置Filter均位于dubbo-rpc
前面章节介绍Protocol的相关实现时,我们已经知道DubboProtocol层暴露出来的接口都是Dubbo内部的一些概念,业务层无法直接使用。为了让业务逻辑能够无缝使用Dubbo,就需要将业务逻辑与Dubbo内部概念打通,这就用到了动态代理的功能。Proxy动态代理层在Dubbo架构中的位置如下所示,Proxy的具体代码实现位于dubbo-rpc-api模块中:Consumer在进行服务调用时,Dubbo会通过动态代理将业务接口实现对象转化为相应的Invoker对象,然后在Cluster层、Protocol层都会使用Invoker;Provider在暴露服务时,也会有Invoker对象与业
通过前面章节对DubboProtocol的讲解,我们知道:对于服务暴露:上层业务Bean会被封装成Invoker对象,然后传入DubboProtocol.export()方法中,Invoker会被封装成DubboExporter,并缓存到exporterMap集合中。在DubboProtocol暴露的ProtocolServer收到请求时,经过一系列解码处理,最终会到达DubboProtocol.requestHandler这个ExchangeHandler对象中,该ExchangeHandler对象会从exporterMap集合中取出Invoker,并调用其invoke()方法处理请求;对于
本章,我将对DubboRPC层的Protocol接口进行详细介绍。Protocol接口的继承关系见下图:一、AbstractProtocolProtocol,顾名思义是对“协议”的抽象,它的核心是export()——暴露服务,以及refer()引用服务这两个方法://Protocol.java@SPI("dubbo")publicinterfaceProtocol{/***默认端口*/intgetDefaultPort();/***将一个Invoker暴露出去,export()方法实现需要是幂等的,即同一个服务暴露多次和暴露一次的效果是相同的*/@Adaptive<T
前面章节,我已经对Dubbo架构中的Remoting层进行了完整介绍,包括Dubbo底层的网络模型以及线程模型。从本章开始,我就开始介绍DubboRemoting上面的一层——RPC层。RPC层对应dubbo-rpc模块,也同样包含很多子层,整个RPC层在Dubbo框架中的位置如下图:本章,我主要针对RPC层的核心接口进行讲解,这些接口大多定义在dubbo-rpc-api中:一、dubbo-rpc模块划分下图展示了dubbo-rpc模块的结构,其中每个子模块对应一种RPC协议:1.1顶层抽象上述的dubbo-rpc-api模块,是Dubbo对Rpc层的顶层抽象,里面定义了很多核心接口,其它du
在前面章节,我已经深入分析了dubbo-remoting模块的Transport子层,并对这一子层的核心接口,以及Client和Server的底层实现进行了讲解。本章,我将对dubbo-remoting模块的Exchange子层进行分析,Exchange层是Transport层的上一层,即DubboRemoting层中的最顶层。Dubbo将信息交换行为抽象成Exchange层,官方文档对这一层的说明是:封装了请求-响应的语义,即关注一问一答的交互模式,实现了同步转异步。在Exchange这一子层,以Request和Response为中心,针对Channel、ChannelHandler、Cli
上一章,我对dubbo-remoting模块Transport层中的Server相关的核心抽象类以及基于Netty4的实现类进行了分析。本章,我继续分析Transport层中的剩余核心接口及实现,主要涉及Client接口、ChannelHandler接口,以及相关的核心组件。一、AbstractClientAbstractClient,是对客户端的抽象,和AbstractServer一样,继承自AbstractEndpoint抽象类:1.1核心字段AbstractClient中的核心字段如下:publicabstractclassAbstractClientextendsAbstractEnd
我在《透彻理解ApacheDubbo(八)——dubbo-remoting模块:核心接口》中,对dubbo-remoting模块的整体结构及核心接口进行过介绍。Remoting层,包括了Exchange、Transport和Serialize三个子层。本章,我就来对Transport子层中的核心接口的实现进行分析。一、AbstractPeer我们首先来看AbstractPeer这个抽象类,它同时实现了Endpoint接口和ChannelHandler接口,是AbstractChannel、AbstractEndpoint抽象类的父类。1.1核心字段AbstractPeer中有四个字段:publ
Buffer是一种字节容器,在JavaNIO、Netty等NIO框架中都有类似的设计。例如,JavaNIO中的ByteBuffer、Netty4中的ByteBuf。Dubbo抽象出了ChannelBuffer接口,用于对底层各种不同的NIO框架中的Buffer进行统一,其子类如下图所示:上述这些Dubbo中的缓冲区相关接口、抽象类及实现类,都定义在dubbo-remoting-api模块中。org.apache.dubbo.remoting.buffer包在更高层面上,抽象了各个NIO框架中的缓冲区概念,同时也提供了一些基础实现:本章,我就按照ChannelBuffer的继承结构,从顶层的Ch
我在前面章节介绍dubbo-registry模块的注册中心功能时,曾对ZookeeperTransporter和ZookeeperClient这两个dubbo-remoting模块中的接口进行过分析。dubbo-remoting模块,提供了多种客户端/服务端通信的功能,上述的Zookeeper通信只是它提供的一个功能。在Dubbo的整体架构设计图中,我们可以看到最底层红色框选中的部分即为Remoting层,其中包括了Exchange、Transport和Serialize三个子层:Serialize子层我在上一章的序列化中已经讲解过了,本章,我主要介绍dubbo-remoting模块的Exch
RPC框架需要通过网络完成跨JVM的通信,既然需要网络通信,就必然涉及使用序列化与反序列化的相关技术。下面我从Java序列化的基础内容开始,介绍常见的序列化算法,最后再分析Dubbo是如何支持这些序列化算法的。一、Java序列化Java语言原生支持序列化,使用起来分为如下几个步骤:被序列化的对象实现Serializable接口;生成一个序列化版本号serialVersionUID,只有序列化和反序列化的serialVersionUID都相同的情况下,才能够成功地反序列化,如果类没有定义serialVersionUID,JDK会随机生成一个;根据需求决定是否要重写writeObject()/re
Dubbo支持多种不同的注册中心实现,从源码的dubbo-registry模块的层级目录就可以看出来:Dubbo官方推荐使用ZooKeeper作为注册中心,所以本章我就来讲解Dubbo对ZooKeeper的集成,并对相关组件的源码进行分析。一、Dubbo目录结构ZooKeeper是一款用于分布式协调的开源中间件。它是一个树型的目录结构,支持变更推送。下面是Dubbo官方文档中的一张图,展示了Dubbo在Zookeeper中的节点层级结构:上图的解释如下:名为dubbo的节点是Dubbo在Zookeeper中的根节点;Service层的节点名称是服务接口的全限定名,比如org.apache.du
上一章,我讲解了dubbo-registry注册中心模块的核心接口,并对AbstractRegistry的公共方法进行了分析,由于AbstractRegistry实现了注册信息的本地缓存,所以即使Consumer节点与注册中心断开了连接,还是可以通过调用AbstractRegistry.getCacheUrls()方法获取本地缓存,从而得到最近注册的ProviderURL。这其实是AbstractRegistry提供的容错机制,保证了服务的可靠性。我们回顾一下Registry的类继承图,可以看到Registry的子类都继承了FailbackRegistry:FailbackRegistry提供
注册中心,在微服务架构中的作用举足轻重:服务提供者(Provider)启动后,会向注册中心完成服务注册;服务消费者(Consumer)启动后,会完成对所需Provider的订阅操作,当Provider发生变化时,Registry会主动推送订阅了该Provider的所有Consumer。本章,我将对dubbo-registry模块中的Registry层进行分析,它在Dubbo架构中所处的位置如下图红框所示:图例说明:图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口;图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的
时间轮,是一种高效的、批量管理定时任务的调度模型。我在《透彻理解Java网络编程》和《透彻理解Kafka》两个专栏中,分别介绍过Netty和Kafka中的时间轮算法实现。在Dubbo中,对时间轮的应用主要体现在如下两个方面:失败重试:例如,Provider向注册中心进行注册失败时的重试操作,或是Consumer向注册中心订阅时的失败重试等;周期性定时任务:例如,定期发送心跳请求,请求超时的处理,或是网络连接断开后的重连机制。本章,我将对ApacheDubbo中的时间轮算法进行讲解。在Dubbo中,实现时间轮算法的思路和Netty几乎是完全一样的:时间轮是一种环形结构,分为很多槽,一个槽代表一个
Dubbo为了更好地达到OCP原则(即“对扩展开放,对修改封闭”的原则),采用了“微内核+插件”的架构。微内核架构中,内核通常采用Factory、IoC、OSGi等方式管理插件生命周期,Dubbo采用SPI机制来加载插件,DubboSPI参考JDK原生的SPI机制,进行了性能优化以及功能增强。本章,我将分为三个部分循序渐进讲解DubboSPI机制:DubboSPI机制中大量运用了“统一配置模型”,这是一种基于URL的接口契约,首先,我对Dubbo的URL统一配置模型进行讲解;DubboSPI机制参考了JDKSPI机制,并对它进行了增强,接着我对JDKSPI机制进行讲解;最后,我将讲解Dubbo
可扩展,分布式系统的一个基本要求。业务系统在从单体架构向集群架构演进的过程中,需要通过负载均衡技术,将流量尽可能均摊到集群中的每台机器上,以此克服单台机器硬件资源的限制,做到横向扩展。ApacheDubbo就是一款高性能、轻量级的开源JavaRPC框架,提供了以下核心能力:面向接口的远程方法调用;可靠、智能的容错和负载均衡;服务自动注册和发现能力。从本系列开始,我将对阿里巴巴开源的这款分布式RPC框架进行深入分析,具体来说,我会:首先,我会从整体到局部的方式,介绍Dubbo的整体架构、核心知识点;接着,我会自底向上剖析Dubbo源码,深入分析Dubbo的工作原理及核心实现;在此期间,我会实现一