说透 Nacos 一致性协议

news2025/1/20 16:22:33

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 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/997071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

透视俄乌网络战之二:Conti勒索软件集团(上)

透视俄乌网络战之一&#xff1a;数据擦除软件 Conti勒索软件集团&#xff08;上&#xff09; 1. Conti简介2. 组织架构3. 核心成员4. 招募途径5. 工作薪酬6. 未来计划参考 1. Conti简介 Conti于2019年首次被发现&#xff0c;现已成为网络世界中最危险的勒索软件之一&#xff0…

汇川PLC学习Day3:轴控代码编写、用户程序结构说明与任务配置示例、

汇川PLC学习Day3&#xff1a;轴控代码编写、用户程序结构说明、任务配置示例 一、新建轴与轴控代码编写 1. 新建轴 (1)新建一个轴 &#xff08;2&#xff09;将轴名字更新为实际名字 可以后面实例化后再更改&#xff0c;汇川可以在更新名字时同步更新其他编写的代码名字&a…

GStreamer时钟同步

播放复杂媒体时&#xff0c;每个audio和video sample必须在特定时间按特定顺序播放。为此&#xff0c;GStreamer提供了一种同步机制&#xff0c;通过使用 GstClock object、buffer timestamps和SEGMENT event来实现&#xff1a; &#xff08;1&#xff09;GstClock&#xff1a;…

Java中如何获取一个字符串是什么类型

Java中如何获取一个字符串是什么类型&#xff1f; 在Java中&#xff0c;您可以使用一些方法来确定一个字符串的类型。下面是一些常用的方法&#xff1a; 使用正则表达式&#xff1a;您可以使用正则表达式来匹配字符串是否符合特定的模式或格式&#xff0c;以确定其类型。例如&…

【Linux入门指北】Linux磁盘扩容

文章目录 1、给 / 分区扩容 Linux在使用过程中由于数据量不断增大&#xff0c;导致磁盘空间不足&#xff0c;需要增加磁盘空间&#xff0c;主要有以下三种方式: 直接给 / 分区&#xff08;或者某一分区&#xff09;扩容&#xff0c;直接在原有磁盘上增大空间给虚拟机新增一块磁…

typeScript 学习笔记(二)

类接口 TypeScript 入门教程 (xcatliu.com) 十四.类 ① 类 类&#xff1a;定义了一件事物的抽象特点&#xff0c;包含它的属性和方法对象&#xff1a;类的实例&#xff0c;通过new生成面向对象&#xff08;OOP&#xff09;的三大特性&#xff1a;封装、继承、多态封装&…

C++学习笔记(重载、类)

C 1、函数重载2、类2.1、类的方法和属性2.2、类的方法的定义2.3、构造器和析构器2.4、基类与子类2.5、类的public、protected、private继承2.6、类的方法的重载2.7、子类方法的覆盖2.8、继承中的构造函数和析构函数 1、函数重载 函数重载大概可以理解为&#xff0c;定义两个名…

Rethink LSTMGRU

LSTM 设计思想 姑且不看偏置。 W W W 和 U U U 是加权的矩阵&#xff0c;写模型的时候用 nn.Linear(in_dim, out_dim) 就成&#xff1b; σ \sigma σ 是 Sigmoid 函数 第一条&#xff0c;遗忘门&#xff0c;定义为 有多少内容需要被遗忘&#xff1b;第二条&#xff1a;输入门…

ES8生产实践——pod日志采集(Fluentd方案)

Fluentd介绍 Fluentd是一个是一个开源的日志收集和传输工具&#xff0c;旨在解决日志数据的收集、传输和处理问题&#xff0c;它可以收集来自于各种系统或应用的日志&#xff0c;转化为用户指定的格式后&#xff0c;转发到用户所指定的日志存储系统之中。 用图来说明问题的话&…

【安装mysql(基础安装+主从复制)】

由于我的 centos 版本是 aarch64 版本 安装链接&#xff1a; 1、aarch64 版本 linux 系统安装 mysql 2、安装完成之后是不能用 navicat 进行直接访问的&#xff0c;需要如下设置&#xff1a; mysql -uroot -proot&#xff08;明文登陆&#xff0c;记得 -uroot 和 -proot之间…

Redis 基础总结

1、NoSQL概述 1.1 数据库分类 目前数据库分&#xff1a;关系型数据库与非关系型数据库 常用的关系型数据库&#xff1a; Oracle&#xff0c;MySQL&#xff0c;SqlServer&#xff0c;DB2 常用的非关系数据库&#xff1a;Redis&#xff0c;MongoDB&#xff0c;ElasticSearch&…

MIT 6.S081学习笔记(第一章)

〇、前言 本章主要是关于实验环境的搭建和完成 LAB UTIL。 平台&#xff1a;阿里云 Ubuntu20.04VScode on macOS&#xff08;M1 Apple Silicon&#xff09;。 一、环境搭建 1、QEMU QEMU&#xff08;quick emulator&#xff09;是一款由法布里斯贝拉&#xff08;Fabrice Bel…

C++中多态的底层实现

1.先来看一波比较容易出错的题 会打印出来什么&#xff1f; 其实打印出来的是B->1;为什么呢&#xff1f;看我如何讲解的。 2.思考为什么只有引用或则指针才能触发多态 结论&#xff1a;子类赋值给父类对象切片&#xff0c;不会拷贝虚标 我听老师上面的解释是&#xff1a;如…

敏捷工具敏捷项目管理实践管理

​Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架&#xff0c;旨在最短时间内交付最大价值。 Leangoo领歌是一款永久免费的专业敏捷研发管理工具&#xff0c;提供敏捷研发解决方案&#xff0c;解决研发痛点&#xff0c;打造成功…

STM32低功耗分析

1.ARM发布最新内核 2023 年5 月 29 日&#xff0c;Arm 公司今天发布了处理器核心&#xff1a;Cortex-X4、Cortex-A720 和Cortex-A520。这些核心都是基于 Arm v9.2 架构&#xff0c;只支持 64 位指令集&#xff0c;不再兼容 32 位应用。Arm 公司表示&#xff0c;这些核心在性能…

性能监控-grafana+prometheus+node_exporter

Prometheus是一个开源的系统监控和报警工具。它由SoundCloud开发并于2012年发布&#xff0c;后来成为了一个独立的开源项目&#xff0c;并得到了广泛的应用和支持。 Prometheus的主要功能包括采集和存储各种系统和应用程序的监控数据&#xff0c;并提供强大的查询语言PromQL来…

Python 之使用Numpy库来加载Numpy(.npy)文件并检查其内容

文章目录 总的介绍data.dtypedata.shapedata.ndimdata.size 总的介绍 要判断一个Numpy&#xff08;.npy&#xff09;文件的数据集类型&#xff0c;你可以使用Python中的Numpy库来加载该文件并检查其内容。以下是一些常见的步骤&#xff1a; 导入Numpy库&#xff1a; 首先&…

【关于存储故障的维修心得】

工具 分享&#xff1a;傲梅分区助手 和 DiskGenius https://www.diskgenius.cn/ https://www.disktool.cn/download.html 傲梅 1&#xff0c;想要不改变文件的情况下&#xff0c;改变某些盘的大小&#xff0c;如C盘&#xff0c;Win11有概率磁盘管理 工具不能压缩卷 扩展卷。…

Idea中如何在一个项目中引入其他子模块?

首先在Settings打开Project Structure&#xff0c;然后找到Modules&#xff0c;点击加号点击import module&#xff0c;将需要引进的module引进来。 然后点击Artifacts 可以看到比如说day22…这个是我现在的项目&#xff0c;day16是我需要引入的。那么就在红色横线上面右键点第…

第六章 图 五、图的深度优先遍历(DFS算法)

目录 一、定义 深度优先遍历通常用于解决以下问题&#xff1a; 深度优先遍历算法具有以下优点&#xff1a; 深度优先遍历算法的一个缺点是&#xff1a; 二、代码 空间复杂度&#xff1a; 时间复杂度&#xff1a; 邻接矩阵存储&#xff1a; 邻接表存储&#xff1a; 三、…