Dubbo: 在springboot中的启动过程

Dubbo: 在springboot中的启动过程,第1张

SpringBoot在启动时,通过ConfigurationClassPostProcessor.postProcessBeanFactory完成对依赖jar包中XxAutopConfiguration类的注册,自然DubboAutoConfiguration也会被注册到容器内部。

DubboAutoConfiguration中,定义了一个ServiceClassPostProcessor ,同样会被注册到容器内。

ServiceClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor接口,同样他也是一个BeanFactoryPostProcessor。

在SpringBoot刷新容器,调用所有BeanFactoryPostProcessors时,对BeanDefinitionRegistryPostProcessor,会去调用其postProcessBeanDefinitionRegistry方法

至此,便将ServiceBean注册进了Spring IOC容器。至于对象和代理对象的创建,那是后话了。

我们知道DubboService会被注册到注册中心,最终的结果是:将服务名、服务对外暴露的url等信息通过网络请求发送到注册中心,那么对外暴露的时机是什么时候?它又是如何做到这件事情的?

关于时机,它应该在容器刷新完成之后将所有DubboService对外暴露,那么如何感知到容器刷新呢?SpringBoot中可以注册listener,容器开始启动、启动完成等事件会通知注册进来的listener。

ServiceClassPostProcessor 除了向容器注册ServiceBean之外,还注册了一个监听器:DubboBootstrapApplicationListener,当感知到容器刷新完成和关闭事件时,做出相应处理,在这里关注刷新完成该如何处理。

启动DubboBootStrap

至于Service如何暴露:如下图

最后服务暴露到底对外暴露了个啥呢?其实就是invoker的url,当consumer发起服务调用的时候,发起请求,当provider接收到请求之后,将请求携带的信息(接口、方法名、参数数组...)封装为Invocation对象,分派到相应的invoker,通过invoker.invoke(invocation)完成调用。

另外敖丙的文章也还不错, Dubbo系列之服务暴露过程

从springboot解析@DubboReference开始讲起。

DubboAutoConfiguration被@EnableDubboConfig注解,通过该注解引入了DubboConfigConfigurationRegistrar类。

DubboConfigConfigurationRegistrar::registerBeanDefinitions(args)

ReferenceAnnotationBeanPostProcessor是一个InstantiationAwareBeanPostProcessorAdapter,在对象实例化后,填充属性中,会调用其postProcessPropertyValues

最终到达referenceBean.get()方法,返回代理对象,并注入到目标对象的field。

如果抛开SpringBoot如何注入被@DubboReference注解的Bean,可以说referenceBean.get()就是服务引用的入口。

后面的事情就是Dubbo内部要完成的了,大概过程如这样:

1、InvokerInvocationHandler jdk动态代理

5、RegistryDirector返回Invokers

Router分为:Script 脚本路由、Condition 条件路由

6、通过MockInvokersSelector的route方法(getNormalInvokers)拿到能正常执行的invokers

8、当回到AbstractClusterInvoker后,执行(默认FailoverClusterInvoker,根据配置的是,Failfast Cluster(快速失败) , Failsafe Cluster(失败安全) , Failback Cluster(失败自动恢复) , Forking Cluster(并行调用多个服务器,只要一个成功即返回) , Broadcast Cluster(广播调用所有提供者,逐个调用,任意一台报错则报错))doInvoker方法

9、FailoverClusterInvoker调用AbstractClusterInvoker的select方法

10、执行doSelect方法

11、调用AbstractLoadbalance的select方法

12、根据配置的负载均衡策略调用对应的(如RoundRobinLoadBalance)类的doSelect方法

13、返回invokers.get()方法

14、调用FailoverClusterInvoker的invoke方法

均继承自抽象类AbstractDirectory

Directory 获取 invoker 是从 methodInvokerMap 中获取的,主要都是读操作,那它的写操作是在什么时候写的呢?就是在回调方法 notify 的时候操作的,也就是注册中心有变化,则更新 methodInvokerMap 和 urlInvokerMap 的值

根据dubbo-admin配置的路由规则来过滤相关的invoker,当我们对路由规则点击启用,就会触发 RegistryDirectory 类的 notify 方法。

notify方法调用refreshInvoker方法。

route方法的实现类为ConditionRoute 根据条件进行过滤

1、调用mathThen方法

2、调用matchCondition方法

3、调用isMatch判断

4、调用isMatchGlobPattern方法

集群模块是服务提供者和服务消费者的中间层,为服务消费者屏蔽了服务提供者的情况,这样服务消费者就可以专心处理远程调用相关事宜。比如发请求,接受服务提供者返回的数据等。这就是Dubbo Cluster集群的作用。

通过cluster来指定集群容错方式

其实就是应对出错情况采取的策略

用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非提供者挂了,再连另一台,自动开启延迟链接,以减少长接数

​ 启动时服务提供者将当前进程启动时间注册到ZK;服务消费者发现该节点后计算服务启动时间(相对当前时间),在默认预热时间的前20%时间内,该节点权重始终固定为2,这样客户端的负载均衡器只会分发极少的请求至节点。

​ 在预热时间之后的80%时间内,该节点权重将随着时间的推移而线性增长;待预热时间到期后,权重自动恢复为默认值100;负载均衡器的内核是一个标准的WLC算法模块,即加权最少连接算法;

​ 如果某个节点Hang住或宕机,其权重会迅速自动调节降低,避免持续性影响;当节点下线时,服务端提前触发权重调节,重载默认权重至1并发布到注册中心,服务消费者将迅速感知到该事件;

服务提供者优雅下线步骤(注意这套逻辑仅在服务端执行)在ok.htm?down=true对应的controller中加入下列逻辑,注意要判断down是否为true,因为正常来说false表示启动验证而不是关机

服务者消费者配置

dubbo服务支持参数动态调整,例如动态调整权重,但dubbo实现方式较为特殊,并不是常规思路。

​ ServiceConfig类拿到对外提供服务的实际类ref,然后通过ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转换(javassistProxyFacory、JdkProxyFactory),接着要做Invoker转换到Export的过程

​ 服务发布:本地暴露、远程暴露

​ 为什么会有 本地暴露 和 远程暴露 呢?不从场景考虑讨论技术的没有意义是.在dubbo中我们一个服务可能既是 Provider ,又是 Consumer ,因此就存在他自己调用自己服务的情况,如果再通过网络去访问,那自然是舍近求远,因此他是有 本地暴露 服务的这个设计.从这里我们就知道这个两者的区别

1、spring启动,解析配置文件

2、创建dubbo标签解析器

3、解析dubbo标签

4、ServiceBean解析

5、容器创建完成,触发ContextRefrestEvent

6、export暴露服务

7、duExportUrls

8、doExportUrlsFor1Protocol

9、getInvoker

10、protocol.export

11、开启服务器 openServer()如nettyServer

12、注册服务到注册中心 registerProvider

Filter 在服务暴露前,做拦截器初始化,在加载所有拦截器时会过滤支队provider生效的数据。

可以。zookeeper的信息会缓存到本地作为一个缓存文件,并且转换成 properties 对象方便使用。建立线程池,定时检测并连接注册中心,失败了就重连。

注册服务到zk其实就是在zk上创建临时节点,当节点下线或者down掉时,即会删除临时节点,从而使服务从可用列表中剔除。

持久节点

临时节点

1、export的时候进行zk订阅

2、设置监听回调的地址,回调给FailbackRegistry的notify

3、创建持久节点

4、设置对该节点的监听

5、更新新的服务信息,服务启动和节点更新回调,都会调用到这里

6、更新缓存文件

7、对比新旧信息是否有变化,有则重新暴露服务

高并发大业务量情况下,暂时屏蔽边缘业务

MockClusterInvoker

​ SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/279293.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-21
下一篇2023-04-21

发表评论

登录后才能评论

评论列表(0条)

    保存