Dubbo使用nacos作为注册中心原理剖析
Nacos是阿里自研的,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台 。作为微服务注册中心,它的目标是淘汰目前流行的eureka,zookeeper等组件。现在学习它真的很有必要。这里就还是从源码的角度出发,看一下Spring Boot是如何和它整合的。详细教程官网已经写的非常明确,这里就不多说了。Nacos中文官方文档下载nacos项目版本:(目前真对spring-cl...
Nacos是阿里自研的,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台 。作为微服务注册中心,它的目标是淘汰目前流行的eureka,zookeeper,consul等组件。现在学习它真的很有必要。这里就还是从源码的角度出发,看一下Spring Boot是如何和它整合的。
详细教程官网已经写的非常明确,这里就不多说了。
Nacos中文官方文档
下载nacos
项目版本:
组件 | 版本 |
---|---|
spring-boot | 2.3.1.RELEASE |
dubbo | 2.7.7.RELEASE |
nacos-server | 1.3.0 |
下载好nacos-server运行包解压后启动(官方有详细文档),这里就不详细说明了。
它的默认端口号是8848 ,这是珠峰的高度,这也表明nacos的志向,要达到珠峰的高度,超高其他同类的产品
Nacos官方文档
架构图:
nacos既可以作为服务注册中心 (Service Registry)。也可以作为配置中心(Configuration Management),本文只讨论作为注册中心的实现原理。
既然作为注册中心,当然有必不可少的两个角色,service provider 和service consumer 。它们的主要的工作流程如下:
其实目前的微服务架构都是这样的工作,dubbo也是如此。
dubbo使用nacos作为注册中心,需要在原有dubbo项目基础上添加如下依赖:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${dubbo.version}</version>
</dependency>
然后将注册中心配置改为如下:
## 其他属性保持不变
## Nacos registry address
dubbo.registry.address = nacos://10.20.153.10:8848
##如果要使用自己创建的命名空间可以使用下面2种方式
#dubbo.registry.address = nacos://10.20.153.10:8848?namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932
#dubbo.registry.parameters.namespace=5cbb70a5-xxx-xxx-xxx-d43479ae0932
...
这里推荐注册时添加nacos的命名空间
这样配置后,重启服务,就能让dubbo的provider和consumer的信息都注册到nacos对应的命名空间下。
如下所示:
dubbo是支持多种注册中心的。对于注册中心。dubbo也同样提供了一个SPI接口:
org.apache.dubbo.registry.RegistryFactory
下面来看RegistryFactory :
@SPI("dubbo")
public interface RegistryFactory {
/**
* Connect to the registry
* <p>
* Connecting the registry needs to support the contract: <br>
* 1. When the check=false is set, the connection is not checked, otherwise the exception is thrown when disconnection <br>
* 2. Support username:password authority authentication on URL.<br>
* 3. Support the backup=10.20.153.10 candidate registry cluster address.<br>
* 4. Support file=registry.cache local disk file cache.<br>
* 5. Support the timeout=1000 request timeout setting.<br>
* 6. Support session=60000 session timeout or expiration settings.<br>
*
* @param url Registry address, is not allowed to be empty
* @return Registry reference, never return empty value
*/
@Adaptive({"protocol"})
Registry getRegistry(URL url);
}
RegistryFactory是一个SPI接口,并且提供一个Adaptive接口。用于获取Registry实例。@SPI中指定了默认实现名是dubbo ,且getRegistry方法对于的自适应实现是protocol .用于创建一个Registry实例。
但是在使用nacos作为注册中心时。会将nacos作为RegistryFactory的默认实现。因此需要从SPI配置文件中去找nacos对应的RegistryFactory实现。
META-INF\dubbo\internal\org.apache.dubbo.registry.RegistryFactory配置文件:
service-discovery-registry=org.apache.dubbo.registry.client.ServiceDiscoveryRegistryFactory
wrapper=org.apache.dubbo.registry.RegistryFactoryWrapper
dubbo=org.apache.dubbo.registry.dubbo.DubboRegistryFactory
multicast=org.apache.dubbo.registry.multicast.MulticastRegistryFactory
zookeeper=org.apache.dubbo.registry.zookeeper.ZookeeperRegistryFactory
redis=org.apache.dubbo.registry.redis.RedisRegistryFactory
consul=org.apache.dubbo.registry.consul.ConsulRegistryFactory
etcd3=org.apache.dubbo.registry.etcd.EtcdRegistryFactory
nacos=org.apache.dubbo.registry.nacos.NacosRegistryFactory
sofa=org.apache.dubbo.registry.sofa.SofaRegistryFactory
multiple=org.apache.dubbo.registry.multiple.MultipleRegistryFactory
因此可以看到。org.apache.dubbo.registry.nacos.NacosRegistryFactory将作为RegistryFactory的实现。来看其源码:
public class NacosRegistryFactory extends AbstractRegistryFactory {
@Override
protected String createRegistryCacheKey(URL url) {
return url.toFullString();
}
@Override
protected Registry createRegistry(URL url) {
return new NacosRegistry(url, createNamingService(url));
}
}
从这里引出核心类NacosRegistry ,结构图如下:
顶层接口是dubbo的RegistryService,它定义了服务的注册到发现的5个基本接口:
public interface RegistryService { // Registry extends RegistryService
/**
* 注册服务.
*
* 注册需处理契约:<br>
* 1. 当URL设置了check=false时,注册失败后不报错,在后台定时重试,否则抛出异常。<br>
* 2. 当URL设置了dynamic=false参数,则需持久存储,否则,当注册者出现断电等情况异常退出时,需自动删除。<br>
* 3. 当URL设置了category=overrides时,表示分类存储,缺省类别为providers,可按分类部分通知数据。<br>
* 4. 当注册中心重启,网络抖动,不能丢失数据,包括断线自动删除数据。<br>
* 5. 允许URI相同但参数不同的URL并存,不能覆盖。<br>
*
* @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
*/
void register(URL url);
/**
* 取消注册服务.
*
* 取消注册需处理契约:<br>
* 1. 如果是dynamic=false的持久存储数据,找不到注册数据,则抛IllegalStateException,否则忽略。<br>
* 2. 按全URL匹配取消注册。<br>
*
* @param url 注册信息,不允许为空,如:dubbo://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
*/
void unregister(URL url);
/**
* 订阅服务.
*
* 订阅需处理契约:<br>
* 1. 当URL设置了check=false时,订阅失败后不报错,在后台定时重试。<br>
* 2. 当URL设置了category=overrides,只通知指定分类的数据,多个分类用逗号分隔,并允许星号通配,表示订阅所有分类数据。<br>
* 3. 允许以interface,group,version,classifier作为条件查询,如:interface=com.alibaba.foo.BarService&version=1.0.0<br>
* 4. 并且查询条件允许星号通配,订阅所有接口的所有分组的所有版本,或:interface=*&group=*&version=*&classifier=*<br>
* 5. 当注册中心重启,网络抖动,需自动恢复订阅请求。<br>
* 6. 允许URI相同但参数不同的URL并存,不能覆盖。<br>
* 7. 必须阻塞订阅过程,等第一次通知完后再返回。<br>
*
* @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
* @param listener 变更事件监听器,不允许为空
*/
void subscribe(URL url, NotifyListener listener);
/**
* 取消订阅服务.
*
* 取消订阅需处理契约:<br>
* 1. 如果没有订阅,直接忽略。<br>
* 2. 按全URL匹配取消订阅。<br>
*
* @param url 订阅条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
* @param listener 变更事件监听器,不允许为空
*/
void unsubscribe(URL url, NotifyListener listener);
/**
* 查询注册列表,与订阅的推模式相对应,这里为拉模式,只返回一次结果。
*
* @see org.apache.dubbo.registry.NotifyListener#notify(List)
* @param url 查询条件,不允许为空,如:consumer://10.20.153.10/com.alibaba.foo.BarService?version=1.0.0&application=kylin
* @return 已注册信息列表,可能为空,含义同{@link org.apache.dubbo.registry.NotifyListener#notify(List<URL>)}的参数。
*/
List<URL> lookup(URL url);
}
然后,构造NacosRegistryService时需要两个必须参数:
① dubbo中的URL对象
URL在我往期的dubbo文章中有介绍,这里就不在
② nacos中的名字服务 (Naming Service)
NacosNamingService是默认实现。它提供分布式系统中所有对象(Object)、实体(Entity)的“名字”到关联的元数据之间的映射管理服务。
例如 ServiceName -> Endpoints Info, Distributed Lock Name -> Lock Owner/Status Info, DNS Domain Name -> IP List, 服务发现和 DNS 就是名字服务的2大场景。
NacosRegistryService相当于一个适配器。dubbo服务的注册与发现的具体实现都是使用NacosNamingService来实现。
具体实现逻辑涉及到了ScheduledExecutorService,HashedWheelTimer,以及一些nacos对外的API接口操作(nacos官网有详细介绍)。服务注册的大致流程已经说清楚了。详细逻辑比较复杂。有兴趣的可以去研究源码。
更多推荐
所有评论(0)