「一文搞懂」Nacos服务注册实现原理

本章内容

服务注册表

服务注册表的主要作用是存储服务注册信息。

服务注册表结构,如图所示:

服务注册表:

// com.alibaba.nacos.naming.core.ServiceManager#serviceMap
Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();

其中:

  • 外层map:
    • key:命名空间(namespace),主要用于环境隔离,如:public、生产环境、测试环境等。
    • value:命名空间下的所有服务信息,是一个map结构。
  • 内层map:
    • key:组名@@服务名称,如:DEFAULT_GROUP@@order-server ,表示分组维度下的服务信息。
    • value:服务信息,是一个Service实例。
  • 服务信息:
    • key:服务集群名称,如:DEFAULT。
    • value:服务集群信息。一个服务集群中可能包含多个服务实例,每个服务实例会包括两个Set结构,用于存储服务对应的临时实例和持久实例。

Service实例:

// com.alibaba.nacos.naming.core.Service#clusterMap
private Map<String, Cluster> clusterMap = new HashMap<>();

Cluster实例:

// com.alibaba.nacos.naming.core.Cluster#persistentInstances
@JsonIgnore
private Set<Instance> persistentInstances = new HashSet<>();
// com.alibaba.nacos.naming.core.Cluster#ephemeralInstances
@JsonIgnore
private Set<Instance> ephemeralInstances = new HashSet<>();

Instance实例:包含InstanceId、IP、Port、健康状态、权重等信息。

Instance示例:

  • instanceId:192.168.31.106#8081#DEFAULT#DEFAULT_GROUP@@order-server。
  • ip:192.168.31.106。
  • port:8081。
  • healthy:true。
  • weight:1.0。
  • ephemeral:true。

服务注册流程

服务(Nacos客户端)启动时,通过调用Nacos服务端服务注册接口将服务信息保存到服务注册表中,完成服务注册。

服务注册接口

请求协议:HTTP(2.x版本新增gRPC)

请求类型:POST

请求路径:/nacos/v1/ns/instance

请求参数

响应编码

客户端

服务(Nacos客户端)启动时,通过监听服务初始化完成事件开启服务注册流程,并调用Nacos服务端提供的服务注册接口完成服务注册。

服务注册流程

如图所示:

处理步骤:

  • 1)服务启动时,Spring容器初始化完成后发布初始化完成事件,AbstractAutoServiceRegistration实现了ApplicationListener接口的onApplicationEvent()方法,因此,会触发AbstractAutoServiceRegistration.onApplicationEvent()方法,通过该方法中调用bind()方法开启服务注册流程。
  • 2)创建服务实例封装服务注册信息。
  • 3)如果实例类型为临时实例,则向Nacos服务端定时(5秒/次)发送心跳请求。
  • 4)组装请求参数,调用服务注册接口向Nacos服务端注册服务实例。

服务端

收到客户端注册请求后,Nacos服务端通过服务注册接口对应的处理方法将服务注册到服务注册表中。

Nacos服务端启动类为nacos-console模块中的com.alibaba.nacos.Nacos类,而在nacos-console模块中引入了nacos-naming模块,nacos-naming模块的controllers包下包含服务注册、服务发现、服务续约等多种类型的控制处理器,其中服务注册对应的控制处理器为:InstanceController。

服务注册流程

如图所示:

图中:

  • 红色部分表示获取服务最新的实例列表。
  • 黄色部分表示更新服务最新的实例信息到注册表中(即:服务注册)。
  • 蓝色部分表示通过Distro协议将服务信息同步给集群中的其他Nacos节点。

处理步骤:

  • 1)Nacos服务端接收客户端注册请求,根据请求参数获取命名空间ID、服务名,并生成对应的服务实例。
  • 2)创建并初始化Service,将其添加到注册表中(针对第一次注册服务)。
  • 3)根据namespaceId,、serviceName从注册表中获取对应的服务信息。
  • 4)根据namespaceId、serviceName、实例类型(临时、持久)生成服务唯一标识。
  • 5)获取最新的实例列表(旧实例列表+待注册实例列表)。
  • 6)根据服务唯一标识前缀判断服务实例类型(临时、持久)选择不同协议进行服务注册与同步(以临时实例为例)。
  • 7)服务注册:
    • 将服务对应的实例列表信息封装成Datum加入到DataStore(数据集)中。
    • 将服务唯一标识、操作类型封装成一个Task任务加入到DistroConsistencyServiceImpl.Notifier的任务队列中。
    • 线程池中的异步线程Notifier通过死循环的方式从任务队列中取出任务进行处理:
      • 更新操作:
        • 更新服务对应的实例列表信息(即:替换旧实例+添加新实例)。
        • 更新服务MD5校验码。
      • 删除操作:
        • 更新服务对应的实例列表信息(即:从服务实例列表中移除实例)。
  • 8)服务信息同步(遍历集群中除自己以外的其他Nacos节点):
    • 将服务信息、资源类型以及目标节点封装成DistroKey。
    • 将DistroKey、操作类型封装成延时任务DelayTask添加到Nacos延时任务执行器的任务集合中。
    • 定时任务通过线程池中的异步处理线程ProcessRunnable从任务集合中取出任务进行数据同步处理。
    • 任务处理失败,则将任务重新加入到任务集合中进行重试。

服务注册常见问题

1)Nacos服务端如何支持高并发注册?

采用队列+异步线程的方式进行服务注册,避免客户端同步将注册信息同步写入注册表。

2)Nacos服务端如何保证并发安全性?

向注册中心注册服务实例时,会对Service对象添加同步锁,保证服务实例信息并发写入的安全性。

3)Nacos服务端如何避免并发读写冲突?

利用CopyOnWrite思想,更新(新增、修改、删除等)服务信息时,先拷贝现有服务信息,生成服务信息副本,在服务信息副本中更新服务信息,更新完成后直接替换现有服务信息,完成服务信息更新。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Nacos是一个开源的动态服务发现、配置管理和服务管理平台。它提供了注册中心、配置中心和命名空间等功能。其中,Nacos注册中心的实现原理如下: Nacos注册中心采用了Raft算法来保证数据的一致性和可靠性。Raft算法是一种分布式一致性算法,它将整个集群划分为多个节点,每个节点都有自己的状态和角色。在Nacos中,每个节点都可以成为Leader、Follower或Candidate。Leader节点负责处理客户端请求,Follower节点负责接收Leader节点的同步请求,Candidate节点则是准备竞选Leader的节点。 当一个服务实例启动时,它会向Nacos注册中心发送注册请求,注册中心会将该服务实例的信息存储在内存中,并将该信息同步给其他节点。当一个服务实例下线时,它会向Nacos注册中心发送注销请求,注册中心会将该服务实例的信息从内存中删除,并将该信息同步给其他节点。 除了服务实例的注册和注销,Nacos注册中心还支持服务实例的心跳检测和服务实例的元数据管理等功能。服务实例的心跳检测可以保证注册中心能够及时发现服务实例的故障,而服务实例的元数据管理可以帮助用户更好地管理服务实例的信息。 总之,Nacos注册中心采用了Raft算法来保证数据的一致性和可靠性,同时支持服务实例的注册、注销、心跳检测和元数据管理等功能,从而实现了一个高可用、高可靠的服务注册中心。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值