Nacos Distro 一致性协议

这篇文章要分享的是 Nacos 集群的 Distro一致性协议。

如下图所示,Nacos Client 向 Nacos Server 集群中的一个服务节点注册信息,这些服务端节点之间再进行数据同步,应用的基础原理就是 Distro 一致性协议。

Distro一致性协议

Distro 协议是 Nacos 对于临时实例数据开发的一致性协议,是阿里巴巴的私有协议。

Distro 的设计机制

新节点同步机制:Nacos 启动时,从其他节点同步数据。

平等机制:Nacos 的每个节点是平等的,都可以处理写的请求。

路由转发机制:客户端发送的写请求,如果属于自己则处理,否则路由转发给其他节点。

异步复制机制:Nacos 把变更的数据异步复制到其他节点。

健康检查机制:每个节点只存了部分数据,定期检查客户端状态保持数据一致性。

本地读机制: 每个节点独立处理读请求,及时从本地发出响应。

Nacos 源码解析

接下来就从 Nacos 源码的角度来学习 Distro 的原理。

新节点同步机制

com.alibaba.nacos.core.distributed.distro.DistroProtocol#startLoadTask

如果此时新加入一个 Nacos Server 节点,会同步从其他节点拉取数据。

java 复制代码
GlobalExecutor.submitLoadDataTask(
                new DistroLoadDataTask(memberManager, distroComponentHolder, DistroConfig.getInstance(), loadCallback));          

看到线程池,便知道这是一个异步任务。

java 复制代码
load();
if (!checkCompleted()) {
   GlobalExecutor.submitLoadDataTask(this, distroConfig.getLoadDataRetryDelayMillis());
} else {
   loadCallback.onSuccess();
   Loggers.DISTRO.info("[DISTRO-INIT] load snapshot data success");
}

一上来先拉取其他节点的数据,只要有一个成功了就算通过。之后再检查是否全量同步成功,没有的话,30秒之后再重新同步一次。

平等机制

com.alibaba.nacos.naming.web.DistroFilter

每个节点处理部分写请求,通过算法计算属于自己的请求就处理,不属于自己的请求转发到正确的节点。

java 复制代码
public boolean responsible(String responsibleTag) {
   final List<String> servers = healthyList;
   
   if (!switchDomain.isDistroEnabled() || EnvUtil.getStandaloneMode()) {
       return true;
   }
   
   if (CollectionUtils.isEmpty(servers)) {
       // means distro config is not ready yet
       return false;
   }
   
   String localAddress = EnvUtil.getLocalAddress();
   int index = servers.indexOf(localAddress);
   int lastIndex = servers.lastIndexOf(localAddress);
   if (lastIndex < 0 || index < 0) {
       return true;
   }
   
   int target = distroHash(responsibleTag) % servers.size();
   return target >= index && target <= lastIndex;
}

路由转发机制

com.alibaba.nacos.naming.web.DistroFilter

路由转发机制和平等机制为上下文关系,不是自己处理的请求,就计算出真正要处理的服务地址,然后转发给它处理。

java 复制代码
final String targetServer = distroMapper.mapSrv(distroTag);

异步复制机制

com.alibaba.nacos.core.distributed.distro.DistroProtocol#sync

如果自己所在的服务端数据发生了变更,就把数据异步复制给集群中的其他节点。

java 复制代码
public void sync(DistroKey distroKey, DataOperation action, long delay) {
    for (Member each : memberManager.allMembersWithoutSelf()) {
        syncToTarget(distroKey, action, each.getAddress(), delay);
    }
}

健康检查机制

服务端集群每个节点处理数据有快有慢,这些数据到底是否全部一致呢?这就需要健康检查机制。线程池提交异步任务,每隔5秒检查一次。

每个服务端节点只负责检查自己负责的客户端的数据是否一致,不是自己对应的客户端不处理。

java 复制代码
private void startVerifyTask() {
   GlobalExecutor.schedulePartitionDataTimedSync(new DistroVerifyTimedTask(memberManager, distroComponentHolder,
                   distroTaskEngineHolder.getExecuteWorkersManager()),
           DistroConfig.getInstance().getVerifyIntervalMillis());
}

本地读机制

com.alibaba.nacos.naming.controllers.InstanceController#list

每个服务端节点最终会存储全部的客户端数据,只要 Nacos Client 请求,会从本地直接返回数据,而不是从其他服务器拉取数据,相当于提升了服务端的响应速度。

数据全部存储在com.alibaba.nacos.naming.core.Service#clusterMap 内存集合中,所以速度非常快。

总结:Distro 协议最关键的部分是每个节点只负责一部分写数据。

相关推荐
一切皆有迹可循13 分钟前
Spring Boot 基于 Cookie 实现单点登录:原理、实践与优化详解
java·spring boot·后端
bing_15832 分钟前
Spring Boot 中 MongoDB @DBRef注解适用什么场景?
spring boot·后端·mongodb
RedJACK~3 小时前
Go语言Stdio传输MCP Server示例【Cline、Roo Code】
开发语言·后端·golang
bing_1583 小时前
Spring Boot 中如何启用 MongoDB 事务
spring boot·后端·mongodb
小屁孩大帅-杨一凡4 小时前
Azure Document Intelligence
后端·python·microsoft·flask·azure
Code哈哈笑6 小时前
【图书管理系统】深度讲解:图书列表展示的后端实现、高内聚低耦合的应用、前端代码讲解
java·前端·数据库·spring boot·后端
无名之逆6 小时前
Hyperlane: Unleash the Power of Rust for High-Performance Web Services
java·开发语言·前端·后端·http·rust·web
薯条不要番茄酱6 小时前
【SpringBoot】从环境准备到创建SpringBoot项目的全面解析.
java·spring boot·后端
caihuayuan513 小时前
升级element-ui步骤
java·大数据·spring boot·后端·课程设计
Kookoos14 小时前
ABP vNext + EF Core 实战性能调优指南
数据库·后端·c#·.net·.netcore