当前位置: 首页 > news >正文

Dubbo如何使用Nacos做注册中心的

Dubbo和Nacos都已经学过一些了,这期来学习一下它俩的集成。

注:Dubbo有接口级和应用级的注册方式,下面是以应用级为讲解。 Dubbo接口级和应用级注册的区别


一、服务注册

1-1、启动时服务注册


服务启动正常注册后在Nacos控制台就可以看到类似下面的信息

在这里插入图片描述


Dubbo自定义了一个 DubboDeployApplicationListener implements ApplicationListener 在这个里面会去调用服务注册的方法 doRegister

@Override
public void doRegister(ServiceInstance serviceInstance) {execute(namingService, service -> {Instance instance = toInstance(serviceInstance);service.registerInstance(instance.getServiceName(), group, instance);});
}

具体调用的地方如下

在这里插入图片描述


完整的调用链路

  1. org.apache.dubbo.config.spring.context.DubboDeployApplicationListener#onApplicationEvent
  2. … 直接断点就可以看了,不全部写出来了
  3. org.apache.dubbo.registry.nacos.NacosServiceDiscovery#doRegister

1-2、心跳检测


在这里插入图片描述

当程序执行完 132行之后,在Nacos上发现服务已经注册上去了,但紧接着在133行进行了断点,且不放行,过一会会发现Nacos上的服务没了。如果放开断点,让程序继续执行,再去Nacos上发现服务又有了,这说明客户端和Nacos服务端是有心跳检测的


心跳检测是由客户端发起的,客户端会启动一个定时任务,定时的去请求服务端

定时任务的入口:com.alibaba.nacos.common.remote.client.RpcClient#start


真正的心跳请求方法如下,当把 currentConnection打上断点,过一会Nacos上的服务就没了,放行断点一会,Nacos上的服务又有了

com.alibaba.nacos.common.remote.client.RpcClient#healthCheck

private boolean healthCheck() {HealthCheckRequest healthCheckRequest = new HealthCheckRequest();if (this.currentConnection == null) {return false;}try {Response response = this.currentConnection.request(healthCheckRequest, 3000L);// not only check server is ok, also check connection is register.return response != null && response.isSuccess();} catch (NacosException e) {// ignore}return false;
}

二、服务发现


Dubbo服务消费者启动时,会从Nacos获取可用的服务提供者列表。每一个可用的服务都会生成一个 invoker,在发起服务调用的时候会选择一个 invoker进行调用

调用者选择的入口如下,可参考 Dubbo消费者一次请求的过程

org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke

public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {List<Invoker<T>> copyInvokers = invokers;// ...for (int i = 0; i < len; i++) {// 选择一个 invoker进行调用Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);try {Result result = invokeWithContext(invoker, invocation);// ...return result;}// ...}// ...
}

2-1、invoker的创建


1、通过接口定义获取服务的提供者的url

在这里插入图片描述


org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener#getAddresses

protected List<URL> getAddresses(ProtocolServiceKey protocolServiceKey, URL consumerURL) {List<ProtocolServiceKeyWithUrls> protocolServiceKeyWithUrlsList =serviceUrls.get(protocolServiceKey.getInterfaceName());List<URL> urls = new ArrayList<>();if (protocolServiceKeyWithUrlsList != null) {for (ProtocolServiceKeyWithUrls protocolServiceKeyWithUrls : protocolServiceKeyWithUrlsList) {if (ProtocolServiceKey.Matcher.isMatch(protocolServiceKey, protocolServiceKeyWithUrls.getProtocolServiceKey())) {urls.addAll(protocolServiceKeyWithUrls.getUrls());}}}if (serviceUrls.containsKey(CommonConstants.ANY_VALUE)) {for (ProtocolServiceKeyWithUrls protocolServiceKeyWithUrls : serviceUrls.get(CommonConstants.ANY_VALUE)) {urls.addAll(protocolServiceKeyWithUrls.getUrls());}}return urls;
}

2、基于生产者的url创建 invoker

org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory#notify
org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory#refreshInvoker
org.apache.dubbo.registry.client.ServiceDiscoveryRegistryDirectory#toInvokers

3、invoker 赋值

org.apache.dubbo.rpc.cluster.directory.AbstractDirectory#setInvokers
org.apache.dubbo.rpc.cluster.directory.AbstractDirectory#refreshInvokerInternal

private synchronized void refreshInvokerInternal() {BitList<Invoker<T>> copiedInvokers = invokers.clone();refreshInvokers(copiedInvokers, invokersToReconnect);refreshInvokers(copiedInvokers, disabledInvokers);validInvokers = copiedInvokers;
}

2-2、项目启动时 invoker初始化流程


最终invoker的创建都是 2-1、invoker的创建,这里只需要知道什么时候去调用的 getAddresses

在这里插入图片描述

2-2、服务端上下线 invoker动态更新


最终invoker的创建都是 2-1、invoker的创建,这里只需要知道什么时候去调用的 getAddresses

注:服务上下线,都是由Nacos服务端通知到这里的

在这里插入图片描述

2-3、invoker的选择与故障转移


再来看一下 org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke,它选择完 invoker并不是就结束了,而是在 for循环里面去处理的,这是因为很有可能之前选择的 invoker是故障的,这时候它会继续去选择其它的 invoker

org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker#doInvoke

public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {List<Invoker<T>> copyInvokers = invokers;String methodName = RpcUtils.getMethodName(invocation);int len = calculateInvokeTimes(methodName);// retry loop.RpcException le = null; // last exception.List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.Set<String> providers = new HashSet<String>(len);for (int i = 0; i < len; i++) {// ...Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);invoked.add(invoker);RpcContext.getServiceContext().setInvokers((List) invoked);boolean success = false;try {Result result = invokeWithContext(invoker, invocation);if (le != null && logger.isWarnEnabled()) {logger.warn(...);}success = true;return result;} catch (RpcException e) {if (e.isBiz()) { // biz exception.throw e;}le = e;} catch (Throwable e) {le = new RpcException(e.getMessage(), e);} finally {if (!success) {providers.add(invoker.getUrl().getAddress());}}}throw new RpcException(...);
}

select 方法入参里面就包含了之前选择过的 invoker,这样就可以排除之前故障的 invoker了

org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#select


/*** 使用负载平衡策略选择调用者。 *      a) 首先,使用负载均衡选择一个调用者。如果此调用程序在先前选择的列表中,或者,如果此调用程序不可用,则继续步骤 b(重新选择),否则返回第一个选定的调用程序 *      b) 重选,重选的生效规则:已选>可用。该规则保证所选择的调用者有最小的机会成为先前选择的列表中的一员,并且还保证该调用者可用。* 参数:*      loadbalance负载均衡策略 *      invocation ——调用 *      invokers ——调用者候选人 *      selected – 是否排除选定的调用者* 返回:最终执行调用的调用者。* 投掷:RpcException异常*/
protected Invoker<T> select( LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException { // ...
}

2-4、serviceUrls 的赋值


获取url的时候都是通过 serviceUrls 获取的,而生成 invoker是基于url,可想而知这个url是关键。当生产者注册和注销的时候,消费者肯定都是要感知的,所以定然有一个通知的机制

设置 serviceUrls,的入口为

org.apache.dubbo.registry.client.event.listener.ServiceInstancesChangedListener#doOnEvent


通知的链路

在这里插入图片描述


三、断开重连


如果Nacos挂掉了,在这之前Dubbo消费者有一个,提供者有2个

序号场景描述结果
1Dubbo消费者和提供者都不变两个提供者正常访问
2Dubbo提供者挂掉了一个一个提供者正常访问
3Dubbo提供者全部挂掉无法访问
4重启Dubbo提供者无法启动成功,因为Nacos连接不上
5Nacos恢复,重启Dubbo提供者正常访问
http://www.dtcms.com/a/601096.html

相关文章:

  • 决策树悲观错误剪枝(PEP)详解:原理、实现与应用
  • 外卖项目 day01
  • 前端vue3 window.open 项目部署后页面404解决办法
  • pc网站 手机网站 微信网站 上海跨境电商官方网站建设
  • Windows 10 C语言编译器安装与配置
  • 网站后台进不去的原因挂机宝做php网站吗
  • Java I/O模型演进 — BIO、NIO与AIO的原理与实战
  • Flutter---泛型
  • 小米Java开发200道面试题及参考答案(上)
  • 【实战】如何优雅的在Win11/10系统下运行Rust编写的binwalk v3.1.1
  • 网站建设费可以计入管理费用吗手机网站开发利用流程
  • MySQL进阶学习笔记:从单表查询到多表关联的深度解析(万字详解)
  • docker一键部署PDF免费工具箱stirling-PDF
  • CI/CD工具Arbess,从安装到入门零基础教程
  • PG预写式日志解码的艺术与应用
  • 通过Swift CSP评估提高金融安全
  • 高可用与高性能数据库配置实践分析(pgSql clickhouse)
  • android sharepreference 的替代品
  • 网站流量分成营销型网站5要素
  • 科技向暖,银发无忧:十五五规划中智慧养老的温度革命
  • UE5 的 Waterline Pro 6的浮力作用机制解析
  • Selenium WebDriver的工作原理?
  • UE5 C++ 定时器 案例练习
  • 6 个成熟的 JS 开源视频编辑项目
  • 网站建设管理维护责任书格式怎样在网站做链接
  • Flutter---Stream
  • 佛山企业网站建设机构南明区住房和城乡建设局网站上
  • 仓颉三方库开发实战:Simple HTTP Server 实现详解
  • 做360网站官网还是百度济南有做五合一网站公司
  • 详细解读视频生成模型Wan2.1代码