目录
2、为什么 Nacos 选择了 Raft 以及 Distro
一、简介
Nacos 起源
Nacos 在阿里巴巴起源于 2008 年五彩石项目(完成微服务拆分和业务中台建设),成长于十年双十⼀的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。 随着云计算兴起,2018 年将 Nacos(阿里内部 Configserver/Diamond/Vipserver 内核) 开源,输出阿里十年的沉淀,推动微服务行业发展,加速企业数字化转型!
Nacos 定位
Nacos/nɑ:k
əʊ
s/ 是 Dynamic
Na
ming and
Co
nfiguration
S
ervice 的首字母简称;⼀个更易于构 建云原生应用的动态服务发现、配置管理和服务管理平台。
官网:
https://nacos.io/
仓库:
https://github.com/alibaba/nacos
Nacos 优势
易⽤:
简单的数据模型,标准的 restfulAPI,易用的控制台,丰富的使用文档。
稳定:
99.9% 高可用,脱胎于历经阿里巴巴 10 年生产验证的内部产品,支持具有数百万服务的大规模场景,具备企业级 SLA 的开源产品。
实时:
数据变更毫秒级推送生效;1w 级,SLA 承诺 1w 实例上下线 1s,99.9% 推送完成;10w 级,SLA 承诺 1w 实例上下线 3s,99.9% 推送完成;100w 级别,SLA 承诺 1w 实例上下线 9s
99.9% 推送完成。
规模:
十万级服务/配置,百万级连接,具备强大扩展性。
二、Nacos 总体设计
1)Nacos 架构
1、设计原则
极简原则,简单才好用,简单才稳定,简单才易协作。
架构⼀致性,⼀套架构要能适应开源、内部、商业化(公有云及专有云)3 个场景。
扩展性,以开源为内核,商业化做基础,充分扩展,方便用户扩展。
模块化,将通用部分抽象下沉,提升代码复用和健壮性。
长期主义,不是要⼀个能支撑未来 3 年的架构,而是要能够支撑 10 年的架构。
开放性,设计和讨论保持社区互动和透明,方便大家协作。
2、架构图
整体架构分为用户层、业务层、内核层和插件,用户层主要解决用户使用的易用性问题,业务层主要解决服务发现和配置管理的功能问题,内核层解决分布式系统⼀致性、存储、高可用等核心问题,插件解决扩展性问题。
3、用户层
OpenAPI
:暴露标准 Rest 风格 HTTP 接口,简单易用,方便多语言集成。
Console
:易用控制台,做服务管理、配置管理等操作。
SDK
:多语言 SDK,目前几乎支持所有主流编程语言。
Agent
:Sidecar 模式运行,通过标准 DNS 协议与业务解耦。
CLI
:命令行对产品进行轻量化管理,像 git ⼀样好用。
4、业务层
服务管理
:实现服务 CRUD,域名 CRUD,服务健康状态检查,服务权重管理等功能。
配置管理
:实现配置管 CRUD,版本管理,灰度管理,监听管理,推送轨迹,聚合数据等功能。
元数据管理
:提供元数据 CURD 和打标能力,为实现上层流量和服务灰度非常关键。
5、内核层
插件机制
:实现三个模块可分可合能力,实现扩展点 SPI 机制,用于扩展自己公司定制。
事件机制
:实现异步化事件通知,SDK 数据变化异步通知等逻辑,是 Nacos 高性能的关键部分。
日志模块
:管理日志分类,日志级别,日志可移植性(尤其避免冲突),日志格式,异常码+帮
助文档。
回调机制
:SDK 通知数据,通过统⼀的模式回调用户处理。接口和数据结构需要具备可扩展性。
寻址模式
:解决 Server IP 直连,域名访问,Nameserver 寻址、广播等多种寻址模式,需要可
扩展。
推送通道
:解决 Server 与存储、Server 间、Server 与 SDK 间高效通信问题。
容量管理
:管理每个租户,分组下的容量,防止存储被写爆,影响服务可用性。
流量管理
:按照租户,分组等多个维度对请求频率,长链接个数,报文大小,请求流控进行控制。
缓存机制
:容灾目录,本地缓存,Server 缓存机制,是 Nacos 高可用的关键。
启动模式
:按照单机模式,配置模式,服务模式,DNS 模式模式,启动不同的模块。
⼀致性协议
:解决不同数据,不同⼀致性要求情况下,不同⼀致性要求,是 Nacos 做到 AP 协
议的关键。
存储模块
:解决数据持久化、非持久化存储,解决数据分片问题。
6、插件
Nameserver
:解决 Namespace 到 ClusterID 的路由问题,解决用户环境与 Nacos 物理环境映射问题。
CMDB
:解决元数据存储,与三方 CMDB 系统对接问题,解决应用,人,资源关系。
Metrics
:暴露标准 Metrics 数据,方便与三方监控系统打通。
Trace
:暴露标准 Trace,方便与 SLA 系统打通,日志白平化,推送轨迹等能力,
并且可以和计量计费系统打通。
接入管理
:相当于阿里云开通服务,分配身份、容量、权限过程。
用户管理
:解决用户管理,登录,SSO 等问题。
权限管理
:解决身份识别,访问控制,角色管理等问题。
审计系统
:扩展接口方便与不同公司审计系统打通。
通知系统
:核心数据变更,或者操作,方便通过
2) Nacos 配置模型
1、概念介绍
配置(Configuration)
在系统开发过程中通常会将⼀些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物 理运行环境进行适配。配置管理⼀般包含在系统部署的过程中,由系统管理员或者运维人员完成这 个步骤。配置变更是调整系统运行时的行为的有效手段之⼀。
配置管理 (Configuration Management)
在 Nacos 中,系统中所有配置的存储、编辑、删除、灰度管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理。 配置服务 (Configuration Service) 在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
配置项Configuration Item)
⼀个具体的可配置的参数与其值域,通常以 param-key = param-value 的形式存在。例如我们常 配置系统的日志输出级别(logLevel = INFO | WARN | ERROR) 就是⼀个配置项。
配置集(Configuration Set)
⼀组相关或者不相关的配置项的集合称为配置集。在系统中,⼀个配置文件通常就是⼀个配置集,包含了系统各个方面的配置。例如,⼀个配置集可能包含了数据源、线程池、日志级别等配置项。
命名空间(Namespace)
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之⼀是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如数据库配置、限流阈值、降级开关)隔离等。如果在没有指定 Namespace 的情况下,默认使用 public 命名空间。
配置组(Group)
Nacos 中的⼀组配置集,是配置的维度之⼀。通过⼀个有意义的字符串(如 ABTest 中的实验组、对照组)对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建⼀个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置项,如 database_url 配置和 MQ_Topic 配置。
配置 ID(Data ID)
Nacos 中的某个配置集的 ID。配置集 ID 是划分配置的维度之⼀。Data ID 通常用于划分系统的配置集。⼀个系统或者应用可以包含多个配置集,每个配置集都可以被⼀个有意义的名称标识。Data ID 尽量保障全局唯⼀,可以参考 Nacos Spring Cloud 中的命名规则:
${prefix}-${spring.profiles.active}-${file-extension}
配置快照(Configuration Snapshot)
Nacos 的客户端 SDK 会在本地生成配置的快照。当客户端无法连接到 Nacos Server 时,可以使用配置快照显示系统的整体容灾能力。配置快照类似于 Git 中的本地 commit,也类似于缓存,会在适当的时机更新,但是并没有缓存过期(expiration)的概念。
2、Nacos 配置模型
1. Nacos 提供可视化的控制台,可以对配置进行发布、更新、删除、灰度、版本管理等功能。
2. SDK 可以提供发布配置、更新配置、监听配置等功能。
3. SDK 通过 GRPC 长连接监听配置变更,Server 端对比 Client 端配置的 MD5 和本地 MD5
是否相等,不相等推送配置变更。
4. SDK 会保存配置的快照,当服务端出现问题的时候从本地获取
三、Nacos 内核设计
1)Nacos ⼀致性协议
1、为什么 Nacos 需要⼀致性协议
Nacos 在开源支持就定下了⼀个目标,尽可能的减少用户部署以及运维成本,做到用户只需要⼀个 程序包,就可以快速以单机模式启动 Nacos 或者以集群模式启动 Nacos。而 Nacos 是⼀个需要 存储数据的⼀个组件,因此,为了实现这个目标,就需要在 Nacos 内部实现数据存储。单机下其 实问题不大,简单的内嵌关系型数据库即可;但是集群模式下,就需要考虑如何保障各个节点之间的数据⼀致性以及数据同步,而要解决这个问题,就不得不引入共识算法,通过算法来保障各个节点之间的数据的⼀致性。
2、为什么 Nacos 选择了 Raft 以及 Distro
为什么 Nacos 会在单个集群中同时运行 CP 协议以及 AP 协议呢?这其实要从 Nacos 的场景出 发的:Nacos 是⼀个集服务注册发现以及配置管理于⼀体的组件,因此对于集群下,各个节点之间 的数据⼀致性保障问题,需要拆分成两个方面
从服务注册发现来看
服务发现注册中心,在当前微服务体系下,是十分重要的组件,服务之间感知对方服务的当前可正 常提供服务的实例信息,必须从服务发现注册中心进行获取,因此对于服务注册发现中心组件的可用性,提出了很高的要求,需要在任何场景下,尽最大可能保证服务注册发现能力可以对外提供服务;同时 Nacos 的服务注册发现设计,采取了心跳可自动完成服务数据补偿的机制。如果数据丢失的话,是可以通过该机制快速弥补数据丢失。
因此,为了满足服务发现注册中心的可用性,强⼀致性的共识算法这里就不太合适了,因为强⼀致性共识算法能否对外提供服务是有要求的,如果当前集群可用的节点数没有过半的话,整个算法直接“罢工”,而最终⼀致共识算法的话,更多保障服务的可用性,并且能够保证在⼀定的时间内各个节点之间的数据能够达成⼀致。
上述的都是针对于 Nacos 服务发现注册中的非持久化服务而言(即需要客户端上报心跳进行服务实例续约)。而对于 Nacos 服务发现注册中的持久化服务,因为所有的数据都是直接使用调用 Nacos服务端直接创建,因此需要由 Nacos 保障数据在各个节点之间的强⼀致性,故而针对此类型的服务数据,选择了强⼀致性共识算法来保障数据的⼀致性。
从配置管理来看
配置数据,是直接在 Nacos 服务端进行创建并进行管理的,必须保证大部分的节点都保存了此配置数据才能认为配置被成功保存了,否则就会丢失配置的变更,如果出现这种情况,问题是很严重的,如果是发布重要配置变更出现了丢失变更动作的情况,那多半就要引起严重的现网故障了,因此对于配置数据的管理,是必须要求集群中大部分的节点是强⼀致的,而这里的话只能使用强⼀致性共识算法。
为什么是 Raft 和 Distro 呢
对于强⼀致性共识算法,当前工业生产中,最多使用的就是 Raft 协议,Raft 协议更容易让人理解, 并且有很多成熟的工业算法实现,比如蚂蚁金服的 JRaft、Zookeeper 的 ZAB、Consul 的 Raft、百度的 braft、Apache Ratis;因为 Nacos 是 Java 技术栈,因此只能在 JRaft、ZAB、Apache Ratis 中选择,但是 ZAB 因为和 Zookeeper 强绑定,再加上希望可以和 Raft 算法库的支持团队随时沟通交流,因此选择了 JRaft,选择 JRaft 也是因为 JRaft 支持多 RaftGroup,为 Nacos 后面的多数据分片带来了可能。
而 Distro 协议是阿里巴巴自研的⼀个最终⼀致性协议,而最终⼀致性协议有很多,比如 Gossip、 Eureka 内的数据同步算法。而 Distro 算法是集 Gossip 以及 Eureka 协议的优点并加以优化而出来的,对于原生的 Gossip,由于随机选取发送消息的节点,也就不可避免的存在消息重复发送给同⼀节点的情况,增加了网络的传输的压力,也给消息节点带来额外的处理负载,而 Distro 算法引入了权威 Server 的概念,每个节点负责⼀部分数据以及将自己的数据同步给其他节点,有效的降低了消息冗余的问题。
3、Nacos 的⼀致性协议层
当前的 Nacos 内核中,已经做到了将⼀致性协议的能力,完全下沉到了内核模块作为 Nacos 的核心能力,很好的服务于服务注册发现模块以及配置管理模块,我们来看看当前 Nacos 的架构。
2)Nacos 自研 Distro 协议
1、背景
Distro 协议是 Nacos 社区自研的⼀种 AP 分布式协议,是面向临时实例设计的⼀种分布式协议,其保证了在某些 Nacos 节点宕机后,整个临时实例处理系统依旧可以正常工作。作为⼀种有状态的中间件应用的内嵌协议,Distro 保证了各个 Nacos 节点对于海量注册请求的统⼀协调和存储。
2、设计思想
Distro 协议的主要设计思想如下:
Nacos 每个节点是平等的都可以处理写请求,同时把新数据同步到其他节点。
每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据⼀致性。
每个节点独立处理读请求,及时从本地发出响应。
下面几节将分为几个场景进行 Distro 协议工作原理的介绍。
-
数据初始化
新加入的 Distro 节点会进行全量数据拉取。具体操作是轮询所有的 Distro 节点,通过向其他的机器发送请求拉取全量数据。
在全量拉取操作完成之后,Nacos 的每台机器上都维护了当前的所有注册上来的非持久化实例数据。
-
数据校验
在 Distro 集群启动之后,各台机器之间会定期的发送心跳。心跳信息主要为各个机器上的所有数据 的元信息(之所以使用元信息,是因为需要保证网络中数据传输的量级维持在⼀个较低水平)。这种数据校验会以心跳的形式进行,即每台机器在固定时间间隔会向其他机器发起⼀次数据校验请求。
⼀旦在数据校验过程中,某台机器发现其他机器上的数据与本地数据不⼀致,则会发起⼀次全量拉取请求,将数据补齐。
-
写操作
对于⼀个已经启动完成的 Distro 集群,在⼀次客户端发起写操作的流程中,当注册非持久化的实例的写请求打到某台 Nacos 服务器时,Distro 集群处理的流程图如下。
整个步骤包括几个部分(图中从上到下顺序):
1、前置的 Filter 拦截请求,并根据请求中包含的 IP 和 port 信息计算其所属的 Distro 责任节点, 并将该请求转发到所属的 Distro 责任节点上。
2、责任节点上的 Controller 将写请求进行解析。
3、Distro 协议定期执行 Sync 任务,将本机所负责的所有的实例信息同步到其他节点上。
-
读操作
由于每台机器上都存放了全量数据,因此在每⼀次读操作中,Distro 机器会直接从本地拉取数据。 快速响应。
这种机制保证了 Distro 协议可以作为⼀种 AP 协议,对于读操作都进行及时的响应。在网络分区 的情况下,对于所有的读操作也能够正常返回;当网络恢复时,各个 Distro 节点会把各数据分片的数据进行合并恢复。
3)Nacos 通信通道