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

相关推荐
程序员cxuan1 小时前
速度太快了!本地可以跑 DeepSeek-V4-Flash 了
人工智能·后端·程序员
阿祖zu2 小时前
芝士就是力量!开源私有化部署与 GitHub 双向同步的个人知识笔记 App
前端·后端·ios
不才不才不不才2 小时前
Spring 源码系列(16): doDispatch 全流程——一次请求的主干链路
java·后端·spring
IT_陈寒2 小时前
SpringBoot自动配置失效?这个隐藏配置坑了我一整晚
前端·人工智能·后端
搜狐技术产品小编20233 小时前
告别“黑盒”与误判:如何用“多智能体对抗辩论”重构内容安全审核系统
后端·多agent
DantyWei3 小时前
controller注册及调用时机
后端
edwarddamon3 小时前
Spring Cloud 配置热更新与 Bean 代理机制梳理
java·后端
码事漫谈4 小时前
我用 Seed Evolving 做了个 AI 小说写作工具
后端
Raas1004 小时前
MAIGateway,魔芋企业级AI网关的FinAPI成本竞争力设计
java·后端·网关·api网关·魔芋ai·finapi·mai gateway
计算机魔术师4 小时前
传统基础架构 - 微服务
大数据·后端·微服务·架构·开发工具·编程语言