说透 Nacos 一致性协议

2023-11-17

1 Nacos ⼀致性协议

1.1 为什么 Nacos 需要⼀致性协议

Nacos尽可能减少用户部署以及运维成本,做到用户只需要⼀个程序包,就快速单机模式启动 Nacos 或集群模式启动 Nacos。而 Nacos 是⼀个需要存储数据的组件,为实现目标,就要在 Nacos 内部实现数据存储。单机问题不大,内嵌关系型数据库即可;但集群模式就要考虑保障各节点间的数据⼀致性及数据同步,就得引入共识算法,通过算法保障各节点间的数据⼀致性。

1.2 为什么 Nacos 选择了 Raft 以及 Distro

Nacos 在单个集群中同时运行 CP 协议及 AP 协议?要从 Nacos 场景出发:Nacos 集服务注册发现及配置管理于⼀体,集群下,各节点间的数据⼀致性保障问题,需拆分成两方面:

① 从服务注册发现来看

服务之间感知对方服务的当前可正常提供服务的实例信息,须从服务发现注册中心获取,因此对服务注册发现中心组件的可用性提出高要求,需在任何场景尽最大可能保证服务注册发现能力可以对外提供服务;同时 Nacos 的服务注册发现设计,采取了心跳可自动完成服务数据补偿的机制。如果数据丢失的话,是可以通过该机制快速弥补数据丢失。

为满足服务发现注册中心的可用性,强⼀致性共识算法不太合适,因为强⼀致性共识算法能否对外提供服务有要求,如当前集群可用节点数没过半,整个算法直接“罢工”,而最终⼀致共识算法更多保障服务可用性,并能保证在⼀定时间内各节点之间数据能达成⼀致。上述都是针对 Nacos 服务发现注册中的非持久化服务(即需客户端上报心跳进行服务实例续约)。

而对 Nacos 服务发现注册中的持久化服务,因为所有数据都是直接调用 Nacos服务端直接创建,因此需由 Nacos 保障数据在各节点间的强⼀致性,因此针对此类型的服务数据,选择强⼀致性共识算法来保障数据⼀致性。

② 配置管理

配置数据直接在 Nacos 服务端进行创建并管理,须保证大部分的节点都保存此配置数据,才能认为配置被成功保存,否则就会丢失配置的变更,问题很严重,如发布重要配置变更出现丢失变更,多半引起严重现网故障,因此对配置数据的管理,须集群中大部分节点强⼀致,这里只能使用强⼀致性共识算法。

③ 为啥是 Raft 和 Distro

强⼀致性共识算法,当前最多使用 Raft 协议,易让人理解,并有很多成熟工业算法实现,如蚂蚁金服 JRaft、Zookeeper ZAB、Consul Raft、百度 braft、Apache Ratis;因为 Nacos 是 Java 技术栈,因此只能在 JRaft、ZAB、ApacheRatis 中选择,但ZAB 和 Zookeeper 强绑定,再加上希望可以和 Raft 算法库支持团队随时沟通交流,因此选择 JRaft,也因为 JRaft 支持多 RaftGroup,为 Nacos 后面的多数据分片带来可能。

而 Distro 协议是阿里巴巴自研的⼀个最终⼀致性协议,最终⼀致性协议很多如 Gossip、Eureka 内的数据同步算法。Distro 算法集 Gossip 及 Eureka 协议优点并优化而出,原生 Gossip由于随机选取发送消息的节点,不可避免存在消息重复发给同⼀节点情况,增加网络传输的压力,也给消息节点带来额外的处理负载,而 Distro 算法引入权威 Server 概念,每个节点负责⼀部分数据及将自己的数据同步给其他节点,有效降低消息冗余问题。

2 早期的 Nacos ⼀致性协议

2.1 早期 Naocs 架构

特点

服务注册和配置管理⼀致性协议 分开,没下沉到 Nacos内核模块作为通用能力

  • 服务发现模块⼀致性协议的实现和服务注册发现模块的逻辑强耦合
  • 充斥服务注册发现的概念

缺点

  • Nacos 服务注册发现模块逻辑复杂难维护,耦合了⼀致性协议层的数据状态
  • 计算存储彻底难以分离
  • 对计算层的无限水平扩容能力也有影响

因此必然要对 Nacos⼀致性协议做抽象及下沉,使其成为 Core 模块能力,彻底让服务注册发现模块只充当计算能力,同时为配置模块去外部数据库存储打下架构基础。

3 当前 Nacos 的⼀致性协议层

当前 Nacos 内核中,已将⼀致性协议的能力完全下沉到内核模块作为 Nacos 核心能力,很好的服务于服务注册发现模块及配置管理模块。

3.1 当前 Nacos 的架构

特点

新 Nacos 架构将⼀致性协议从原先服务注册发现模块下沉到内核模块,并尽可能提供统⼀抽象接口,使上层的服务注册发现模块及配置管理模块,不再耦合任何⼀致性语义。

优点

解耦抽象分层后,每个模块能快速演进,并且性能和可用性都大幅提升。

4 Nacos 如何做到⼀致性协议下沉

既然 Nacos 将 AP、CP 协议下沉到内核模块:

且尽可能保持了⼀样的使用体验。那这⼀致性协议下沉如何做到的?

⼀致性协议抽象

其实,⼀致性协议,就是用来保证数据⼀致的,而数据的产生,必然有⼀个写入的动作;同时还要能够读数据,并且保证读数据的动作以及得到的数据结果,并且能够得到⼀致性协议的保障。因此,⼀致性协议最最基础的两个方法,就是写动作和读动作

public interface ConsistencyProtocol<T extends Config, P extends RequestProcessor> extends CommandOperations {

    /**
     * Obtain data according to the request.
     */
    Response getData(ReadRequest request) throws Exception;

    /**
     * 同步数据提交,在 Datum 中已携带相应的数据操作信息
     */
    Response write(WriteRequest request) throws Exception;
}

任何使用⼀致性协议的,只需使用 getData 及 write 方法。

⼀致性协议抽象在 consistency 包,Nacos 对 AP、CP ⼀致性协议接口使用抽象都在,且实现具体⼀致性协议时,采用插件可插拔,进⼀步将⼀致性协议具体实现逻辑和服务注册发现、配置管理两个模块解耦。

package com.alibaba.nacos.core.distributed;

/**
 * Conformance protocol management, responsible for managing the lifecycle of conformance protocols in Nacos.
 */
@SuppressWarnings("all")
@Component(value = "ProtocolManager")
public class ProtocolManager extends MemberChangeListener implements DisposableBean {

    private void initAPProtocol() {
        ApplicationUtils.getBeanIfExist(APProtocol.class, protocol -> {
            Class configType = ClassUtils.resolveGenericType(protocol.getClass());
            Config config = (Config) ApplicationUtils.getBean(configType);
            injectMembers4AP(config);
            protocol.init(config);
            ProtocolManager.this.apProtocol = protocol;
        });
    }

    private void initCPProtocol() {
        ApplicationUtils.getBeanIfExist(CPProtocol.class, protocol -> {
            Class configType = ClassUtils.resolveGenericType(protocol.getClass());
            Config config = (Config) ApplicationUtils.getBean(configType);
            injectMembers4CP(config);
            protocol.init(config);
            ProtocolManager.this.cpProtocol = protocol;
        });
    }
}

仅做完⼀致性协议抽象还不够:

  • 服务注册发现及配置管理还是要依赖⼀致性协议接口,在两个计算模块中耦合了带状态的接口
  • 虽然做了比较高度的⼀致性协议抽象,服务模块及配置模块却依然还是要在自己代码模块去显式处理⼀致性协议的读写请求逻辑
  • 需要自己去实现⼀个对接⼀致性协议的存储

服务发现及配置模块,更应专注数据使用及计算,而非数据咋存储、咋保障数据⼀致性,数据存储及多节点⼀致问题应交由存储层保证。

为了:

  • 降低⼀致性协议出现在服务注册发现及配置管理两模块的频次
  • 尽可能让⼀致性协议只在内核模块中感知

Nacos又做数据存储抽象。

5 数据存储抽象

⼀致性协议是为保证数据⼀致,如利用⼀致性协议实现存储,那服务模块以及配置模块,就由原来的依赖⼀致性协议接口转为依赖存储接口,而存储接口后面具体实现就比⼀致性协议丰富,且服务模块、配置模块也无需为直接依赖⼀致性协议而承担多余编码工作(快照、状态机实现、数据同步)。使这两模块可更专注自己核心逻辑。对于数据抽象,这里仅以服务注册发现模块为例:

package com.alibaba.nacos.core.storage.kv;

public interface KvStorage {

    enum KvType {
        /**
         * Local file storage.
         */
        File,

        /**
         * Local memory storage.
         */
        Memory,

        /**
         * RocksDB storage.
         */
        RocksDB,
    }
  // ...
}

由于 Nacos 的服务模块存储,更多是根据单或多个唯⼀ key 去执行点查,因此KV存储接口最适合。接口定义后,就是这KVStore具体实现。可直接将 KVStore 实现对接 Redis,DB或直接根据 Nacos 内核模块的⼀致性协议,在此基础之上,实现⼀个内存或者持久化的分布式强(弱)⼀致性 KV。

通过功能边界将 Nacos 进程进⼀步分离为计算逻辑层和存储逻辑层,计算层和存储层之间的交互仅通过薄薄数据操作胶水代码,就在单个 Nacos 进程里面实现计算、存储彻底分离。

存储层

进⼀步实现插件化的设计,对于中小公司且有运维成本要求的话,可以直接使用 Nacos 自带的内嵌分布式存储组件来部署⼀套 Nacos 集群。

服务实例数据以及配置数据的量级很大的话,并且本身有⼀套比较好的 Paas 层服务,那么完全可以复用已有的存储组件,实现 Nacos 的计算层与存储层彻底分离。

本文由博客一文多发平台 OpenWrite 发布!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

说透 Nacos 一致性协议 的相关文章

  • 如何使用Spring WebClient进行同步调用?

    Spring Framework in 休息模板 https docs spring io spring framework docs current javadoc api org springframework web client R
  • 使用 JDBC 获取 Oracle 11g 的最后插入 ID

    我是使用 Oracle 的新手 所以我将放弃之前已经回答过的内容这个问题 https stackoverflow com questions 3131064 get id of last inserted record in oracle
  • Guice 忽略注入构造函数参数上的 @Nullable

    我正在使用 Guice v 3 0 并且有一个值被注入到构造函数中 该值可以为 null 因此我在构造函数中使用 Nullable 来自 javax annotations 注释了该参数 public MyClass Parameter1
  • 带有 Android 支持库 v7 的 Maven Android 插件

    我使用 maven android plugin 构建我的 android 应用程序 它依赖于 android 支持库 v4 和 v7 由于我没有找到如何从developer android com下载整个sdk 因此我无法使用maven
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • Base36 编码字符串?

    我一直在网上查找 但找不到解决此问题的方法 在 Python Ruby 或 Java 中 如何对以下字符串进行 Base 36 编码 nOrG9Eh0uyeilM8Nnu5pTywj3935kW 5 Ruby 以 36 为基数 s unpa
  • 将SQL数据引入jquery availabletag

    我正在尝试制作自动完成文本框 但如何将 SQL 数据包含到 jquery 可用标记并循环它 我无法根据以下代码执行该功能 任何帮助 将不胜感激 谢谢 这是我的预期输出 预期结果演示 http jsfiddle net VvETA 71 jq
  • 文本在指定长度后分割,但不要使用 grails 打断单词

    我有一个长字符串 需要将其解析为长度不超过 50 个字符的字符串数组 对我来说 棘手的部分是确保正则表达式找到 50 个字符之前的最后一个空格 以便在字符串之间进行彻底的分隔 因为我不希望单词被切断 public List
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • 是否可以从 servlet 内部以编程方式设置请求上下文路径?

    这是一个特殊情况 我陷入了处理 企业 网络应用程序的困境 企业应用程序正在调用request getContext 并将其与另一个字符串进行比较 我发现我可以使用 getServletContext getContextPath 获取 se
  • 从休眠乐观锁定异常中恢复

    我有一个这样的方法 Transactional propagation Propagation REQUIRES NEW public void doSomeWork Entity entity dao loadEntity do some
  • 在 Java 中通过 XSLT 分解 XML

    我需要转换具有嵌套 分层 表单结构的大型 XML 文件
  • 如何删除日期对象的亚秒部分

    当 SQL 数据类型为时间戳时 java util Date 存储为 2010 09 03 15 33 22 246 如何在存储记录之前将亚秒设置为零 例如 在本例中为 246 最简单的方法是这样的 long time date getTi
  • JAVA中遍历JSON数据

    我是 JSON 新手 我使用 HTTPUrlConnections 并在 JAVA 程序中获得一些响应 响应数据将类似于 data id 1 userId 1 name ABC modified 2014 12 04 created 201
  • 使用Java绘制维恩图

    我正在尝试根据给定的布尔方程绘制维恩图 例如 a AND b AND c我想在 Android 手机上执行此操作 因此我需要找到一种使用 Java 来执行此操作的方法 我找到了一个完美的小部件 它可以完成我在这方面寻找的一切布尔代数计算器
  • 替换文件中的字符串

    我正在寻找一种方法来替换文件中的字符串而不将整个文件读入内存 通常我会使用 Reader 和 Writer 即如下所示 public static void replace String oldstring String newstring
  • JMS 中的 MessageListener 和 Consumer 有什么区别?

    我是新来的JMS 据我了解Consumers能够从队列 主题中挑选消息 那么为什么你需要一个MessageListener因为Consumers会知道他们什么时候收到消息吗 这样的实际用途是什么MessageListener 编辑 来自Me
  • 记录类名、方法名和行号的性能影响

    我正在我的 java 应用程序中实现日志记录 以便我可以调试应用程序投入生产后可能出现的潜在问题 考虑到在这种情况下 人们不会奢侈地使用 IDE 开发工具 以调试模式运行事物或单步执行完整代码 因此在每条消息中记录类名 方法名和行号将非常有
  • ArrayList.clear() 和 ArrayList.removeAll() 有什么区别?

    假如说arraylist定义为ArrayList
  • 如何使用通配符模拟泛型方法的行为

    我正在使用 EasyMock 3 2 我想基于 Spring Security 为我的部分安全系统编写一个测试 我想嘲笑Authentication http docs spring io autorepo docs spring secu

随机推荐

  • Python bs4怎么安装?

    bs4是BeautifulSoup4的简称 它是一个可以从HTML中提取数据的Python第三方库 具体来讲 bs4可以从茫茫的HTML代码中准确查找出你想要的内容 甚至一个小小的字符串 听起来是不是感觉bs4很厉害的样子 那么 Pytho
  • 预测模型的评价指标Matlab

    一般情况下 所要预测的数据分为连续型数据和离散性数据 连续型数据比如成绩分数 时间序列等 离散性数据通常为划分的分类标签 针对不同的数据类型 衡量模型的准确程度采用不同指标 如比较一些算法的准确率 若预测的数据为离散型 则算法的准确性自然容
  • 【综合转贴】CSS “点 ”“井号”的含义and ID class区别.

    body font family Arial sans serif color 333333 line height 1 166 margin 0px padding 0px masthead margin 0 padding 10px 0
  • 【3月比赛合集】45场可报名的数据挖掘奖金赛,任君挑选!

    CompHub 实时聚合多平台的数据类 Kaggle 天池 和OJ类 Leetcode 牛客 比赛 本账号同时会推送最新的比赛消息 欢迎关注 更多比赛信息见 CompHub主页 或 点击文末阅读原文 以下信息仅供参考 以比赛官网为准 目录
  • k8s部署之ETCD集群

    k8s部署之ETCD集群 1 etcd下载 etcd下载地址 https github com coreos etcd releases 从github etcd的发布页面选取相应的版本用 wget url 来下载 如 wget https
  • 【易售小程序项目】小程序首页(展示商品、商品搜索、商品分类搜索)【后端基于若依管理系统开发】

    文章目录 界面效果 界面实现 工具js 页面 首页 让文字只显示两行 路由跳转传递对象 将商品分为两列显示 使用中划线划掉原价 后端 商品 controller service mapper sql 同项目其他文章 界面效果 说明 界面中商
  • Docker容器中如何运行一个带GUI的app?

    问 How can you run GUI apps in a docker container Are there any images that set up vncserver or something so that you can
  • 图像处理之-----插值算法

    插值算法是图像处理中最基本的算法 首先我们先了解一下什么是插值算法 以及插值算法在图像处理过程中的应用 1 什么是插值 Interpolation is a method of constructing new data points wi
  • Redis 密码设置和查看密码

    Redis 密码设置和查看密码 redis没有实现访问控制这个功能 但是它提供了一个轻量级的认证方式 可以编辑redis conf配置来启用认证 1 初始化Redis密码 在配置文件中有个参数 requirepass 这个就是配置redis
  • Python软件开发之需求实现:数据结构、数据类型。自动化软件测试必会

    一 有这样的一个需求 判断学生成绩是否及格 二 拿到这样的一个需求如何进行需求分析呢 做为测试人员 我们只有明确需求后 才不容易漏测 需求分析阶段 一 看到这样的一句话之后我们有几个问题需求和产品经理确认的 1 什么样的算及格 60 70分
  • Spark 启动集群 Master 正常启动 Worker 不启动

    在学习spark过程中遇到的问题 做下记录 这个问题网上出现的不再少数 出现问题的原因也是各不相同 并且没有一个人的问题和我完全一样 我高兴得都快哭了 顺着大家的思路 尝试了两个多小时才搞明白 问题的根源大多都在于 hostname 的配置
  • C++ STL - vector 模拟实现+解析迭代器

    目录 vector使用 vector模拟实现 vector实现解析 memcpy进行元素拷贝问题 扩容问题 vector迭代器解析 vector迭代器失效问题 1 示例一 一个典型的迭代器失效bug insert实现 2 示例二 inser
  • 记录一些可能会用到资料

    1 win11子系统WSL修改用户密码 以管理员身份打开 PowerShell 输入命令 wsl exe user root passwd root 修改 root 用户密码 2 layDate控件在页面高度不够的情况下闪退 在laydat
  • 8x8LED点阵

    点量这个只需要把9高电平 13低电平就可以了 共阳极点阵 行线是led的正极 列线是led的列线 左上角点亮 显示多个灯是动态扫描的 一个一个显示的 然后间隔速度要快就可以造成显示 点阵由两篇74Hc595级联在一起驱动的 只需要三个io口
  • matplotlib输出图形到网页_Python实操:手把手教你用Matplotlib把数据画出来

    导读 获取数据之后 而不知道如何查看数据 用途还是有限的 幸好 我们有Matplotlib Matplotlib 是基于 NumPy 数组构建的多平台数据可视化库 它是John Hunter 在2002年构想的 原本的设计是给 IPytho
  • 【LeetCode与《代码随想录》】哈希表篇:做题笔记与总结-JavaScript版

    文章目录 代码随想录 主要题目 242 有效的字母异位词 349 两个数组的交集 202 快乐数 1 两数之和 经典哈希 454 四数相加 II 15 三数之和 双指针 18 四数之和 双指针 相关题目 383 赎金信 49 字母异位词分组
  • mnist数据集之自己写的数字

    这是我自己用画图3D写的数字0 9 然后又把它们修改成了28 28像素的格式 并经过测试后输出了预测值 不知道怎么搞得 顺序打乱了 这是我测试后的结果 要加油哦
  • C语言——执行创建多个文件同时写入内容

    代码 include
  • Python3, 多种方法实现文件/目录的监听,只想说一个字:泰裤辣。

    多种方法实现文件 目录监听 1 引言 2 代码实战 2 1 os模块 2 2 watchdog库 2 2 1 安装 2 2 2 示例 2 3 inotify 2 3 1 安装 2 3 2 示例 3 总结 1 引言 小屌丝 鱼哥 帮我看下这段
  • 说透 Nacos 一致性协议

    1 Nacos 致性协议 1 1 为什么 Nacos 需要 致性协议 Nacos尽可能减少用户部署以及运维成本 做到用户只需要 个程序包 就快速单机模式启动 Nacos 或集群模式启动 Nacos 而 Nacos 是 个需要存储数据的组件