Nacos作为Dubbo注册中心时Consumer更新Provider的机制

目录

一、RegistryDirectory

二、NacosRegistry

三、NacosNamingService

四、HostReactor

1、立即获取更新

 2、定时更新配置

五、EventDispatcher

六、PushReceiver

七、获取最新Provider实例的三种方式

八、新增加Provider的日志分析


一、RegistryDirectory

Consumer端启动时,Dubbo的RegistryDirectory中向Nacos发起订阅,并把自己做为回调通知的Listenering执行器:

当Nacos中注册的Provider实例有发生变化时,会及时的收到回调通知,RegistryDirectory.notify(List<URL> urls)方法会被调用,用于处理接收到的新的Provider实例:

二、NacosRegistry

RegistryDirectory的subscribe(URL url)方法通过NacosRegistry中的doSubscribe(...)方法,往Nacos服务端发起注册及获取Provider信息:

方法doSubscribe(URL, NotifyListener)中根据Consumer端的url生成对应的Provider服务名称,如此时consumer的url如下:

consumer://192.168.22.198/cn.raysonblog.shopserviceprovider.service.RpcShopService?application=shop-service-consumer&category=providers,configurators,routers&dubbo=2.0.2&generic=false&interface=cn.raysonblog.shopserviceprovider.service.RpcShopService&lazy=false&logger=log4j2&methods=sayHello,getConfigServiceName&pid=397&qos.enable=false&release=2.7.3&side=consumer&sticky=false&timestamp=1629807903321

此时生成的Provider服务名称serviceNames为:

providers:cn.raysonblog.shopserviceprovider.service.RpcShopService::

三、NacosNamingService

在方法doSubscribe(URL, NotifyListener, Set<String>)中通过namingService.getAllInstances(serviceName)获取当前Consumer对应服务的所有Provider节点,namingService代表的类为NacosNamingService ,在该类中会通过getAllInstances(...)方法调用HostReactor的getServiceInfo方法获取ServiceInfo对象:

四、HostReactor

getServiceInfo(...)方法会判断本地是否已经有Provider节点信息,如果没有则通过updateServiceNow(...)立即从Nacos服务获取:

 以下将立即获取更新及将更新加到定时任务中分别说明。

1、立即获取更新

updateServiceNow(...)方法中是通过HTTP请求向Nacos获取最新的配置信息:

此处的serverProxy对象是NamingProxy类的实例,queryList(...)方法:

会调用Nacose服务的接口“/nacos/v1/ns/instance/list”获取数据,传入的参数:

  • namespaceId:指定获取配置的命名空间,dubbo可以通过配置项dubbo.registry.address中的nacos地址中增加namespace参数进行指定,如下所示:

  • serviceName:当前Consumer应用的要获取的Provider的服务名称,Consumer自动生成,类似如下所示:
DEFAULT_GROUP@@providers:cn.raysonblog.shopserviceprovider.service.RpcShopService::
  • clusters:暂时不清楚,代码中也没有注释,默认情况下是new了一个空的ArrayList<String>,到这里时该参数的值ArrayList中的值按英文逗号分隔后的拼接:StringUtils.join(clusters, ","),因而其值还是空字符串"";
  • udpPort:用于接收Nacos的UDP连接的端口,Nacos服务端往当前应用发送推送消息时,就往该端口推送,接收UDP的实现为PushReceiver,后面单独介绍该实现;
  • clientIp:当前应用所在服务器的IP地址,用于接收Nacos服务的UDP推送等;
  • healthOnly:用于指定是否只获取健康的Provider示例,默认值为false,跟了一下queryList方法的调用,共有三个地方且都在HostReactor中,传入的值都是false,因而目前还没有发现可以通过配置修改该值;

调用Nacos服务获取Provider信息的接口,可能成功也可能失败,如果失败则不更新Provider的信息;如果成功则会比较本地与从服务端获取的进行刷新时间的比较,以便于确认其是否为过期服务等验证,验证通过后才会使用新的Provider信息更新本地的Provider信息,如下HostReactor.processServiceJSON(String)方法所示:

 2、定时更新配置

定时更新是方法scheduleUpdateIfAbsent(serviceName, clusters)调用其中的addTask方法增加到定时任务中:

public synchronized ScheduledFuture<?> addTask(UpdateTask task) {
    return executor.schedule(task, DEFAULT_DELAY, TimeUnit.MILLISECONDS);
}

初次执行周期延迟为DEFAULT_DELAY,默认值为1000,即1秒。

 其中UpdateTask为真正执行的线程,检查是否有新的Provider节点信息,实现如下:

 通过UpdateTask的线程实现可以得知,Nacos作为注册中心时,Consumer会通过HostReactor中的UpdateTask线程间隔10秒去服务端拉取最新的Provider信息实现的,作为对监听即时回调的补充,避免由于监听回调用处理失败导致不能够获取到完整的Provider实例的问题

五、EventDispatcher

HostReactor.processServiceJSON(String)方法会调用EventDispatcher.serviceChanged(ServiceInfo)方法,将变化的ServiceInfo加入到名为changedServices的LinkedBlockingQueue队列中,然后会通过EventDispatcher中的线程Notifier进行处理:

EventListener会调用Dubbo服务提供者变更通知NotifyListener的实现类RegistryDirectory,通知Dubbo Consumer端发起对这些可用Provider的连接,如果原来有连接也会重新发起连接,后面会有操作步骤及日志展示。

六、PushReceiver

PushReceiver为Consumer接收Nacos服务端UDP通知的监听器,以单独的线程进行监听,分为三种消息类型:dom、service及dump,dom及service消息类型都是服务端给Consumer发送消息,如Provider节点变更消息,然后通过hostReactor.processServiceJSON(...)处理这些信息,如下图红枉中的代码所示;dump消息类型为服务端希望获取Consumer的中现在的Provider信息:

但是不论我是增加新的Provider还是断掉Provider,该线程就从来没有读取到数据,说明Nacos服务端没有通过UDP消息的方式往客户端推送消息,那问题来了,Nacos服务端会在什么时候触发UDP通知呢?

七、获取最新Provider实例的三种方式

综上所述,Nacos做为Dubbo注册中心时,获取到最新的Provider实例有以下三种方式:

1、通过注册的回调处理的org.apache.dubbo.registry.integration.RegistryDirectory.notfity()方法,即时的接收实例变更的回调用;

2、通过线程com.alibaba.nacos.client.naming.core.HostReactor.UpdateTask定期的去查询当前应用的Provider实例,避免由于监听回调用处理失败导致不能够获取到完整的Provider实例的问题;

3、通过UDP服务com.alibaba.nacos.client.naming.core.PushReceiver线程,接收Provider实例变化的通知,虽然在本次调试中没有触发这样的请求,但是其应该是有触发机制的。

八、新增加Provider的日志分析

现在已经启动一台Provider以及一台Consumer,现在观察一下新增加Provider时,Consumer在获取到新的Provider,除了对新节点进行重连以下,是否会重新对已经存在Provider再次发起连接。

启动第二台Provider 2

先看一下启动第二个Provider节点的启动日志:

55分19秒启完成,55分20秒显示成功注册到Nacos。

查看Consumer此时的日志变化:

 Consumer在55分21秒的时候显示收到Nacos的通知,并在同一秒的时间成功与Provider连接。

通过上面的日志可以看到,Provider在启动成功后的秒钟之内,Consumer收到通知并成功与Provider进行连接。

与此同时Provider 1的日志控制台有重新注册到Nacos的日志:

启动第三台Provider 3

先看一下启动第三个Provider节点的启动日志:

 56分17秒启完成,56分18秒显示成功注册到Nacos。

查看Consumer此时的日志变化:

Consumer在56分21秒的时候显示收到Nacos的通知,并在同一秒的时间成功与Provider连接。

通过上面的日志可以看到,Provider在启动成功后的秒钟之内,Consumer收到通知并成功与Provider进行连接。

与此同时Provider 1的日志控制台有重新注册到Nacos的日志:

与此同时Provider 2的日志控制台有重新注册到Nacos的日志: 

通过以上几个Provider的加入及日志分析,说明Consumer有重新往原来已经建立了连接的Provider发起了建立连接的请求。 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值