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 协议最关键的部分是每个节点只负责一部分写数据。

相关推荐
用户21411832636027 小时前
Qwen3-Coder 实战!历史人物短视频一键生成,多分镜人物不崩,魔搭直接玩
后端
追逐时光者7 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 54 期(2025年9.8-9.14)
后端·.net
追逐时光者7 小时前
C#/.NET/.NET Core编程技巧练习集,配套详细的文章教程讲解!
后端·.net
AD钙奶-lalala7 小时前
SpringBoot实现WebSocket服务端
spring boot·后端·websocket
moxiaoran57538 小时前
Flask学习笔记(一)
后端·python·flask
你的人类朋友8 小时前
🔒什么是HMAC
后端·安全·程序员
盖世英雄酱581369 小时前
Read timed out问题 排查
java·数据库·后端
BXCQ_xuan9 小时前
软件工程实践二:Spring Boot 知识回顾
java·spring boot·后端
o0o_-_10 小时前
【go/gopls/mcp】官方gopls内置mcp server使用
开发语言·后端·golang
苏三说技术10 小时前
为什么不建议在 Docker 中跑 MySQL?
后端