1.总体设计
1.1 架构图
整体架构分为用户层、业务层、内核层和插件,用户层主要解决用户使用的易用性问题,业务层主要解决服务发现和配置管理的功能问题,内核层解决分布式系统⼀致性、存储、高可用等核心问题,插件解决扩展性问题。
1.1.1 用户层
- OpenAPI:暴露标准 Rest 风格 HTTP 接口,简单易用,方便多语言集成。
- Console:易用控制台,做服务管理、配置管理等操作。
- SDK:多语言 SDK,目前几乎支持所有主流编程语言。
- Agent:Sidecar 模式运行,通过标准 DNS 协议与业务解耦。
- CLI:命令行对产品进行轻量化管理,像 git ⼀样好用。
1.1.2 业务层
- 服务管理:实现服务 CRUD,域名 CRUD,服务健康状态检查,服务权重管理等功能。
- 配置管理:实现配置管 CRUD,版本管理,灰度管理,监听管理,推送轨迹,聚合数据等功能。
- 元数据管理:提供元数据 CURD 和打标能力,为实现上层流量和服务灰度非常关键。
1.1.3 内核层
插件机制:实现三个模块可分可合能力,实现扩展点 SPI 机制,用于扩展自己公司定制。
1.事件机制:实现异步化事件通知,SDK 数据变化异步通知等逻辑,是Nacos 高性能的关键部分。
2.日志模块:管理日志分类,日志级别,日志可移植性(尤其避免冲突),日志格式,异常码+帮助文档。
3.回调机制:SDK 通知数据,通过统⼀的模式回调用户处理。接口和数据结构需要具备可扩展性。
4.寻址模式:解决 Server IP 直连,域名访问,Nameserver 寻址、广播等多种寻址模式,需要可扩展。
5.推送通道:解决 Server 与存储、Server 间、Server 与 SDK 间高效通信问题。
6.容量管理:管理每个租户,分组下的容量,防止存储被写爆,影响服务可用性。
7.流量管理:按照租户,分组等多个维度对请求频率,长链接个数,报文大小,请求流控进行控制。
8.缓存机制:容灾目录,本地缓存,Server 缓存机制,是 Nacos 高可用的关键。
9.启动模式:按照单机模式,配置模式,服务模式,DNS 模式模式,启动不同的模块。
10.⼀致性协议:解决不同数据,不同⼀致性要求情况下,不同⼀致性要求,是Nacos 做到AP协议的关键。
11.存储模块:解决数据持久化、非持久化存储,解决数据分片问题。
1.1.3 插件层
- Nameserver:解决 Namespace 到 ClusterID 的路由问题,解决用户环境与Nacos 物理环境映射问题。
- CMDB:解决元数据存储,与三方 CMDB 系统对接问题,解决应用,人,资源关系。
- Trace:暴露标准 Trace,方便与 SLA 系统打通,日志白平化,推送轨迹等能力,并且可以和计量计费系统打通。
- 接入管理:相当于阿里云开通服务,分配身份、容量、权限过程。
- 用户管理:解决用户管理,登录,SSO 等问题。
- 权限管理:解决身份识别,访问控制,角色管理等问题。
- 审计系统:扩展接口方便与不同公司审计系统打通。
- 通知系统:核心数据变更,或者操作,方便通过 SMS 系统打通,通知到对应人数据变更。
1.2 配置模型
1.2.1 概念介绍
配置
在系统开发过程中通常会将⼀些需要变更的参数、变量等从代码中分离出来独立管理,以独立的配置文件的形式存在。目的是让静态的系统工件或者交付物(如 WAR,JAR 包等)更好地和实际的物 理运行环境进行适配。
配置管理
在 Nacos 中,系统中所有配置的存储、编辑、删除、灰度管理、历史版本管理、变更审计等所有与配置相关的活动统称为配置管理
配置服务
在服务或者应用运行过程中,提供动态配置或者元数据以及配置管理的服务提供者。
配置项
⼀个具体的可配置的参数与其值域,通常以 param-key = param-value 的形式存在。例如我们常配置系统的日志输出级别(logLevel = INFO | WARN | ERROR) 就是⼀个配置项。
配置集
⼀组相关或者不相关的配置项的集合称为配置集。在系统中,⼀个配置文件通常就是⼀个配置集,包含了系统各个方面的配置。例如,⼀个配置集可能包含了数据源、线程池、日志级别等配置项。
命名空间
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之⼀是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如数据库配置、限流阈值、降级开关)隔离等。如果在没有指定 Namespace 的情况下,默认使用 public 命名空间。
配置组
Nacos 中的⼀组配置集,是配置的维度之⼀。通过⼀个有意义的字符串(如 ABTest 中的实验组、对照组)对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建⼀个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置项,如 database_url 配置和 MQ_Topic 配置。
配置ID
Nacos 中的某个配置集的 ID。配置集 ID 是划分配置的维度之⼀。Data ID 通常用于划分系统的配置集。⼀个系统或者应用可以包含多个配置集,每个配置集都可以被⼀个有意义的名称标识。Data ID 尽量保障全局唯⼀
配置快照
Nacos 的客户端 SDK 会在本地生成配置的快照。当客户端无法连接到 Nacos Server 时,可以使用配置快照显示系统的整体容灾能力。配置快照类似于 Git 中的本地 commit,也类似于缓存,会在适当的时机更新,但是并没有缓存过期(expiration)的概念。
1.2.2 基础配置模型
- Nacos 提供可视化的控制台,可以对配置进行发布、更新、删除、灰度、版本管理等功能。
- SDK 可以提供发布配置、更新配置、监听配置等功能。
- SDK 通过 GRPC 长连接监听配置变更,Server 端对比 Client 端配置的 MD5 和本地 MD5是否相等,不相等推送配置变更。
- SDK 会保存配置的快照,当服务端出现问题的时候从本地获取。
1.2.3 配置资源模型
Namespace 的设计就是用来进行资源隔离的,我们在进行配置资源的时候可以从以下两个角度来看:
1.单租户
我们要配置多套环境的配置,可以根据不同的环境来创建 Namespace 。比如开发环境、测试环境、线上环境,我们就创建对应的 Namespace(dev、test、prod),Nacos 会自动生成对应的 Namespace Id 。如果同⼀个环境内想配置相同的配置,可以通过Group 来区分。如下图所示:
2.多组户
每个租户都可以有自己的命名空间。我们可以为每个用户创建⼀个命名空间,并给用户分配对应的权限,比如多个租户(zhangsan、lisi、wangwu),每个租户都想有⼀套自己的多环境配置,也就是每个租户都想配置多套环境。那么可以给每个租户创建⼀个 Namespace (zhangsan、lisi、wangwu)。同样会生成对应的 Namespace Id。然后使用 Group 来区分不同环境的配置。如下图所示:
1.2.3 配置存储模型
Nacos 存储配置有几个比较重要的表分别是:
1.config_info 存储配置信息的主表,里面包含 dataId、groupId、content、tenantId、encryptedDataKey 等数据。
2.config_info_beta 灰度测试的配置信息表,存储的内容和 config_info 基本相似。有⼀个 beta_ips 字段用于客户端请求配置时判断是否是灰度的 ip。
3.config_tags_relation 配置的标签表,在发布配置的时候如果指定了标签,那么会把标签和配置的关联信息存储在该表中。
4.his_config_info 配置的历史信息表,在配置的发布、更新、删除等操作都会记录⼀条数据,可以做多版本管理和快速回滚。
2.内核设计
2.1 一致性协议
集群模式下,保障各个节点之间的数据⼀致性以及数据同步,引入共识算法,通过算法来保障各个节点之间的数据的⼀致性。
2.1.1 为什么Nacos选择了Raft 及 以及 Distro
nacos 是⼀个集服务注册发现以及配置管理于⼀体的组件,因此对于集群下,各个节点之间的数据⼀致性保障问题,需要拆分成两个方面
1.服务注册发现
Nacos 服务发现注册中的非持久化服务时,服务之间感知对方服务的当前可正常提供服务的实例信息,必须从服务发现注册中心进行获取,因此对于服务注册发现中心组件的可用性,提出了很高的要求,需要在任何场景下,尽最大可能保证服务注册发现能力可以对外提供服务;同时 Nacos 的服务注册发现设计,采取了心跳可自动完成服务数据补偿的机制。如果数据丢失的话,是可以通过该机制快速弥补数据丢失。最终⼀致共识算法的话,更多保障服务的可用性,并且能够保证在⼀定的时间内各个节点之间的数据能够达成⼀致
Nacos 服务发现注册中的持久化服务时,所有的数据都是直接使用调用 Nacos服务端直接创建,因此需要由 Nacos 保障数据在各个节点之间的强⼀致性,故而针对此类型的服务数据,选择了强⼀致性共识算法来保障数据的⼀致性
2.配置管理
配置数据,是直接在 Nacos 服务端进行创建并进行管理的,必须保证大部分的节点都保存了此配置数据才能认为配置被成功保存了,否则就会丢失配置的变更,如果出现这种情况,问题是很严重的,如果是发布重要配置变更出现了丢失变更动作的情况,那多半就要引起严重的现网故障了,因此对于配置数据的管理,是必须要求集群中大部分的节点是强⼀致的,而这里的话只能使用强⼀致性共识算法。
3.为什么选择Raft 及 以及 Distro
对于强⼀致性共识算法,有很多成熟的工业算法实现比如蚂蚁金服的 JRaft、Zookeeper 的 ZAB、Consul 的 Raft、
百度的 braft、Apache Ratis;因为 Nacos 是 Java 技术栈,因此只能在 JRaft、ZAB、ApacheRatis 中选择,但是 ZAB 因为和 Zookeeper 强绑定,再加上希望可以和 Raft 算法库的支持团队随时沟通交流,因此选择了 JRaft,选择 JRaft 也是因为 JRaft 支持多 RaftGroup,为 Nacos 后面的多数据分片带来了可能。
而 Distro 协议是阿里巴巴自研的⼀个最终⼀致性协议,而最终⼀致性协议有很多,比如 Gossip、Eureka 内的数据同步算法。而 Distro 算法是集 Gossip 以及 Eureka 协议的优点并加以优化而出来的,对于原生的 Gossip,由于随机选取发送消息的节点,也就不可避免的存在消息重复发送给同⼀节点的情况,增加了网络的传输的压力,也给消息节点带来额外的处理负载,而 Distro 算法引入了权威 Server 的概念,每个节点负责⼀部分数据以及将自己的数据同步给其他节点,有效的降低了消息冗余的问题。
2.2 自研Distro协议
背景介绍
Distro 协议是 Nacos 社区自研的⼀种 AP 分布式协议,是面向临时实例设计的⼀种分布式协议, 其保证了在某些 Nacos 节点宕机后,整个临时实例处理系统依旧可以正常工作。作为⼀种有状态 的中间件应用的内嵌协议,Distro 保证了各个 Nacos 节点对于海量注册请求的统⼀协调和存储
2.2.1 设计思想
Distro 协议的主要设计思想如下:
1.Nacos 每个节点是平等的都可以处理写请求,同时把新数据同步到其他节点。
2.每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据⼀致性。
3.每个节点独立处理读请求,及时从本地发出响应。
2.2.2 Distro 协议工作场景
2.2.2.1 数据初始化
新加入的 Distro 节点会进行全量数据拉取。具体操作是轮询所有的 Distro 节点,通过向其他的机 器发送请求拉取全量数据。在全量拉取操作完成之后,Nacos 的每台机器上都维护了当前的所有注册上来的非持久化实例数 据。
2.2.2.2 数据校验
在 Distro 集群启动之后,各台机器之间会定期的发送心跳。心跳信息主要为各个机器上的所有数据 的元信息(之所以使用元信息,是因为需要保证网络中数据传输的量级维持在⼀个较低水平)。这 种数据校验会以心跳的形式进行,即每台机器在固定时间间隔会向其他机器发起⼀次数据校验请求。⼀旦在数据校验过程中,某台机器发现其他机器上的数据与本地数据不⼀致,则会发起⼀次全量拉 取请求,将数据补齐
2.2.2.3 写操作
对于⼀个已经启动完成的 Distro 集群,在⼀次客户端发起写操作的流程中,当注册非持久化的实例 的写请求打到某台 Nacos 服务器时,Distro 集群处理的流程图如下。
- 前置的 Filter 拦截请求,并根据请求中包含的 IP 和 port 信息计算其所属的 Distro 责任节点, 并将该请求转发到所属的 Distro 责任节点上。
- 责任节点上的 Controller 将写请求进行解析。
- Distro 协议定期执行 Sync 任务,将本机所负责的所有的实例信息同步到其他节点上。
2.2.2.4 读操作
由于每台机器上都存放了全量数据,因此在每⼀次读操作中,Distro 机器会直接从本地拉取数据。 快速响应。这种机制保证了 Distro 协议可以作为⼀种 AP 协议,对于读操作都进行及时的响应。在网络分区 的情况下,对于所有的读操作也能够正常返回;当网络恢复时,各个 Distro 节点会把各数据分片的 数据进行合并恢复
小结
Distro 协议是 Nacos 对于临时实例数据开发的⼀致性协议。其数据存储在缓存中,并且会在启动 时进行全量数据同步,并定期进行数据校验。
在 Distro 协议的设计思想下,每个 Distro 节点都可以接收到读写请求。所有的 Distro 协议的请 求场景主要分为三种情况:
- 当该节点接收到属于该节点负责的实例的写请求时,直接写入。
- 当该节点接收到不属于该节点负责的实例的写请求时,将在集群内部路由,转发给对应的节点, 从而完成读写。
- 当该节点接收到任何读请求时,都直接在本机查询并返回(因为所有实例都被同步到了每台机 器上)。
Distro 协议作为 Nacos 的内嵌临时实例⼀致性协议,保证了在分布式环境下每个节点上面的服务 信息的状态都能够及时地通知其他节点,可以维持数十万量级服务实例的存储和⼀致性。
2.3 Nacos 通信通道
2.3.1 nacos 长链接
2.3.1.1 nacos 1.x 现状
Nacos 1.x 版本 Config/Naming 模块各自的推送通道都是按照自己的设计模型来实现的。
2.3.1.2 场景分析
1.配置
1.1 SDK与Server
1.客户端 SDK 需要感知服务节点列表,并按照某种策略选择其中⼀个节点进行连接;底层连接断开时,需要进行切换 Server 进行重连。
2.客户端基于当前可用的长链接进行配置的查询,发布,删除,监听,取消监听等配置领域的 RPC 语意接口通信。
3.感知配置变更消息,需要将配置变更消息通知推送当前监听的客户端;网络不稳定时,客户端接收失败,需要支持重推,并告警。
4.感知客户端连接断开事件,将连接注销,并且清空连接对应的上下文,比如监听信息上下文清理。
1.2 Server与Server
1.单个 Server 需要获取到集群的所有 Server 间的列表,并且为每⼀个 Server 创建独立的长链
接;连接断开时,需要进行重连,服务端列表发生变更时,需要创建新节点的长链接,销毁下
线的节点长链接。
2.Server 间需要进行数据同步,包括配置变更信息同步,当前连接数信息,系统负载信息同步,
负载调节信息同步等。
2.服务
2.1 SDK与Server
1.客户端 SDK 需要感知服务节点列表,并按照某种策略选择其中⼀个节点进行连接;底层连接
断开时,需要切换 Server 进行重连。
2.客户端基于当前可用的长链接进行配置的查询,注册,注销,订阅,取消订阅等服务发现领域
的 RPC 语意接口通信。
3.感知服务变更,有服务数据发生变更,服务端需要推送新数据到客户端;需要有推送 ack,方
便服务端进行 metrics 和重推判定等。
4.感知客户端连接断开事件,将连接注销,并且清空连接对应的上下文,比如该客户端连接注册
的服务和订阅的服务。
2.2 Server与Server
1.服务端之间需要通过长连接感知对端存活状态,需要通过长连接汇报服务状态(同步 RPC 能
力)。
2.服务端之间进行 AP Distro 数据同步,需要异步 RPC 带 ack 能力。
2.3.1.3 长链接核心诉求
1. 功能性诉求
-
1.1 客户端
1.连接生命周期实时感知能力,包括连接建立,连接断开事件。
2.客户端调用服务端支持同步阻塞,异步 Future,异步 CallBack 三种模式。
3.底层连接自动切换能力。
4.响应服务端连接重置消息进行连接切换。
5.选址/服务发现。 -
1.2 服务端
1.连接生命周期实时感知能力,包括连接建立,连接断开事件。
2.服务端往客户端主动进行数据推送,需要客户端进行 Ack 返回以支持可靠推送,并且需要进行失败重试。
3.服务端主动推送负载调节能力。
2.性能需求
能够支持百万级的长链接规模及请求量和推送量,并且要保证足够稳定。
3.负载均衡
1.常见的负载均衡策略:随机,hash,轮询,权重,最小连接数,最快响应速度等
2.短连接和长链接负载均衡的异同:在短连接中,因为连接快速建立销毁,“随机,hash,轮询,权重”四种方式大致能够保持整体是均衡的,服务端重启也不会影响整体均衡,其中“最小连接数,最快响应速度”是有态的算法,因为数据延时容易造成堆积效应;长连接因为建立连接后,如果没有异常情况出现,连接会⼀直保持,断连后需要重新选择⼀个新的服务节点,当出现服务节点发布重启后,最终连接会出现不均衡的情况出现,“随机,轮询,权重”的策略在客户端重连切换时可以使用,“最小连接数,最快响应速度”和短连接⼀样也会出现数据延时造成堆积效应。长连接和短连接的⼀个主要差别在于在整体连接稳定时,服务端需要⼀个 rebalance 的机制,将集群视角的连接数重新洗牌分配,趋向另外⼀种稳态
-
3.客户端随机+服务端柔性调整核心的策略是客户端+服务端双向调节策略,客户端随机选择+服务端运行时柔性调整。
- 3.1 客户端随机
客户端在启动时获取服务列表,按照随机规则进行节点选择,逻辑比较简单,整体能够保持随机。
- 3.1 客户端随机
- 3.2 服务端柔性调整
1.(当前实现版本)人工管控方案:集群视角的系统负载控制台,提供连接数,负载等视图(扩展新增连接数,负载,CPU 等信息,集群间 report 同步),实现人工调节每个 Server 节点的连接数,人工触发 reblance,人工削峰填谷。
2.提供集群视角的负载控制台:展示 总节点数量,总长链接数量,平均数量,系统负载信息。
3.每个节点的地址,长链接数量,与平均数量的差值,正负值。
4.对高于平均值的节点进行数量调控,设置数量上限(临时和持久化),并可指定服务节点进行切换。
5.(未来终态版本)自动化管控方案:基于每个 server 间连接数及负载自动计算节点合理连接数,自动触发 reblance,自动削峰填谷。实现周期较长,比较依赖算法准确性。
- 3.2 服务端柔性调整
4.连接生命周期
-
4.1心跳保活机制
2.4 寻址机制
naocs集群模式下集群内的每个 Nacos 成员都需要相互通信。因此这就带来⼀个问题,该以何种方式去管理集群内的 Nacos 成员节点信息,而这,就是 Nacos 内部的寻址机制。
2.4.1 单机寻址
单机模式的寻址模式很简单,其实就是找到自己的 IP:PORT 组合信息
2.4.2 文件寻址
文件寻址模式是 Nacos 集群模式下的默认寻址实现。文件寻址模式很简单,其实就是每个 Nacos
节点需要维护⼀个叫做 cluster.conf 的文件。
192.168.16.101:8847
192.168.16.102
192.168.16.103
2.4.3 地址服务器寻址
地址服务器寻址模式是 Nacos 官方推荐的⼀种集群成员节点信息管理,该模式利用了⼀个简易的
web 服务器,用于管理 cluster.conf 文件的内容信息,这样,运维人员只需要管理这⼀份集群成员
节点内容即可,而每个 Nacos 成员节点,只需要向这个 web 节点定时请求当前最新的集群成员节
点列表信息即可。
3.服务发现模块
3.1 注册中心的设计原理
-
数据模型
nacos的数据模型是一种服务-集群-实例
-
数据隔离模型
Nacos 1.0.0 介绍的另外⼀个新特性是:临时实例和持久化实例。在定义上区分临时实例和持久化
实例的关键是健康检查的方式。临时实例使用客户端上报模式,而持久化实例使用服务端反向探测Nacos 1.0.0 特性是:临时实例和持久化实例。在定义上区分临时实例和持久化实例的关键是健康检查的方式。临时实例使用客户端上报模式,而持久化实例使用服务端反向探测,不能去自动摘除下线的实例。(同⼀个服务下可以同时存在持久化
实例和非持久化实例)
Nacos 2.0 中继续沿用了持久化及非持久化的设定,但是有了⼀些调整。在 Nacos2.0 中我们将是否持久化的数据抽象至服务级别,且不再允许⼀个服务同时存在持久化实例和非持久化实例,实例的持久化属性继承自服务的持久化
属性。
- 数据一致性
因为 Dubbo 服务往 Zookeeper 注册的就是临时节点,需要定时发心跳到 Zookeeper来续约节点,并允许服务下线时,将 Zookeeper 上相应的节点摘除。Zookeeper 使用 ZAB 协议虽然保证了数据的强⼀致,但是它的机房容灾能力的缺乏,无法适应⼀些大型场景。
目前nacos的⼀致性协议实现,⼀个是基于简化的 Raft 的 CP ⼀致性,⼀个是基于自研协议 Distro 的
AP ⼀致性。Raft 协议不必多言,基于 Leader 进行写入,其 CP 也并不是严格的,只是能保证⼀
半所见⼀致,以及数据的丢失概率较小。Distro 协议则是参考了内部 ConfigServer 和开源 Eureka,
在不借助第三方存储的情况下,实现基本大同小异。Distro 重点是做了⼀些逻辑的优化和性能的调
优。
- 负载均衡
Nacos 试图做的是将服务端负载均衡与客户端负载均衡通过某种机制结合起来,提供用户扩展性,并给予用户充分的自主选择权和轻便的使用方式。负载均衡是⼀个很大的话题,当我们在关注注册中心提供的负载均衡策略时,需要注意该注册中心是否有我需要的负载均衡方式,使用方式是否复杂。如果没有,那么是否允许我方便的扩展来实现我需求的负载均衡策略。
- 健康检查
Nacos 目前支持临时实例使用心跳上报方式维持活性,发送心跳的周期默认是 5 秒,Nacos 服务端会在 15 秒没收到心跳后将实例设置为不健康,在 30 秒没收到心跳时将这个临时实例摘除
客户端健康检查和服务端健康检查有⼀些不同的关注点。客户端健康检查主要关注客户端上报心跳的方式、服务端摘除不健康客户端的机制。而服务端健康检查,则关注探测客户端的方式、灵敏度及设置客户端健康状态的机制。
1.客户端检查
只需要等待心跳,然后刷新TTL,可以随时摘除不健康实例,减轻服务端的压力-
2.服务端检查
需要服务端根据注册服务配置的健康检查方式,去执行相应的接口,判断相应的返回结果,并做好重试机
制和线程池的管理
无法摘除不健康实例,这意味着只要注册过的服务实例,如果不调用接口主动注销,这些服务实例都需要去维持健康检查的探测任务
Nacos 既支持客户端的健康检查,也支持服务端的健康检查,同⼀个服务可以切换健康检查模式。
性能与容量
nacos淘汰zookeeper原因
1.Zookeeper 舍弃了服务发现的基本功能如健康检查、友好的查询接口
2.Paxos 协议本限制了 Zookeeper 集群的规模(节点越多,投票选举过程越长)
3.当大量的实例上下线时,Zookeeper 的表现并不稳定,同时在推送机制上的缺陷,会引起客户端的资源占用上升,从而性能急剧下降nacos 淘汰eureka原因
压测eureka服务实例在5000台左右会出现服务不可用,在1000左右时正常使用集群扩展性
Nacos 支持两种模式的部署,⼀种是和 Eureka ⼀样的 AP 协议的部署,这种模式只支持临时实例,可以完美替代当前的 Zookeeper、Eureka,并支持机房容灾。另⼀种是支持持久化实例的 CP 模式,这种情况下不支持双机房容
3.2 注册中心服务数据模型
3.2.1 服务和服务实例
定义服务
在 Nacos 中,服务的定义包括以下几个内容:
- 1.命名空间(Namespace):Nacos 数据模型中最顶层、也是包含范围最广的概念,用于在类似环境或租户等需要强制隔离的场景中定义。Nacos 的服务也需要使用命名空间来进行隔离。
- 2.分组(Group):Nacos 数据模型中次于命名空间的⼀种隔离概念,区别于命名空间的强制隔离属性,分组属于⼀个弱隔离概念,主要用于逻辑区分⼀些服务使用场景或不同应用的同名服务,最常用的情况主要是同⼀个服务的测试分组和生产分组、或者将应用名作为分组以防止不同应用
- 3.服务名(Name):该服务实际的名字,⼀般用于描述该服务提供了某种功能或能力。
服务元数据
服务的定义只是为服务设置了⼀些基本的信息,用于描述服务以及方便快速的找到服务,而服务的
元数据是进⼀步定义了 Nacos 中服务的细节属性和描述信息。主要包含:
1.健康保护阈值(ProtectThreshold):为了防止因过多实例故障,导致所有流量全部流入剩余实例,继而造成流量压力将剩余实例被压垮形成的雪崩效应。应将健康保护阈值定义为⼀个 0 到 1之间的浮点数。当域名健康实例数占总服务实例数的比例小于该值时,无论实例是否健康,都会将这个实例返回给客户端。这样做虽然损失了⼀部分流量,但是保证了集群中剩余健康实例能正常工作
2.实例选择器(Selector):用于在获取服务下的实例列表时,过滤和筛选实例。该选择器也被称为路由器,目前 Nacos 支持通过将实例的部分信息存储在外部元数据管理 CMDB 中,并在发现服务时使用 CMDB 中存储的元数据标签来进行筛选的能力。
3.拓展数据(extendData):用于用户在注册实例时自定义扩展的元数据内容,形式为 K-V 。可以在服务中拓展服务的元数据信息,方便用户实现自己的自定义逻辑。
定义实例
由于服务实例是具体提供服务的节点,因此 Nacos 在设计实例的定义时,主要需要存储该实例的⼀些网络相关的基础信息,主要包含以下内容:
- 1.网络 IP 地址:该实例的 IP 地址,在 Nacos2.0 版本后支持设置为域名。
- 网络端口:该实例的端口信息。
- 健康状态(Healthy):用于表示该实例是否为健康状态,会在 Nacos 中通过健康检查的手段进行维护。
- 4.集群(Cluster):用于标示该实例归属于哪个逻辑集群。
- 5.拓展数据(extendData):用于用户自定义扩展的元数据内容,形式为 K-V。可以在实例中拓展该实例的元数据信息,方便用户实现自己的自定义逻辑和标示该实例
实例元数据
和服务元数据不同,实例的元数据主要作用于实例运维相关的数据信息。主要包含:
- 1.权重(Weight):实例级别的配置。权重为浮点数,范围为 0-10000。权重越大,分配给该实例的流量越大。
- 2.上线状态(Enabled):标记该实例是否接受流量,优先级大于权重和健康状态。用于运维人员在不变动实例本身的情况下,快速地手动将某个实例从服务中移除。
- 3.拓展数据(extendData):不同于实例定义中的拓展数据,这个拓展数据是给予运维人员在不变动实例本身的情况下,快速地修改和新增实例的扩展数据,从而达到运维实例的作用
持久化属性
Nacos 提供两种类型的服务:持久化服务和非持久化服务,分别给类 DNS 的基础的服务组件场景和上层实际业务服务场景使用。为了标示该服务是哪种类型的服务,需要在创建服务时选择服务的持久化属性。考虑到目前大多数使用动态服务发现的场景为非持久化服务的类型(如 Spring Cloud,Dubbo,Service Mesh 等),Nacos 将缺醒值设置为了非持久化服务
在 Nacos2.0 版后,⼀个服务只能被定义成持久化服务或非持久化服务,⼀旦定义完成,在服务生命周期结束之前,无法更改其持久化属性。
持久化属性将会影响服务及实例的数据是否会被 Nacos 进行持久化存储,设置为持久化之后,实例将不会再被自动移除,需要使用者手动移除实例
集群(Cluster)
集群是 Nacos 中⼀组服务实例的⼀个逻辑抽象的概念,它介于服务和实例之间,是⼀部分服务属性的下沉和实例属性的抽象
- 定义集群
- 1.在 Nacos 中,集群中主要保存了有关健康检查的⼀些信息和数据:健康检查类型HealthCheckType):使用哪种类型的健康检查方式,目前支持:TCP,HTTP,MySQL;设置为 NONE 可以关闭健康检查。
- 2.健康检查端口(HealthCheckPort):设置用于健康检查的端口。
- 3.是否使用实例端口进行健康检查(UseInstancePort):如果使用实例端口进行健康检查,将会使用实例定义中的网络端口进行健康检查,而不再使用上述设置的健康检查端口进行。
-
4.拓展数据(extendData):用于用户自定义扩展的元数据内容,形式为 K-V 。可以自定义扩展该集群的元数据信息,方便用户实现自己的自定义逻辑和标示该集群
生命周期
-
1.服务生命周期
服务的生命周期相对比较简单,是从用户向注册中心发起服务注册的请求开始,到用户主动发起删除服务的请求或⼀定时间内服务下没有实例(无论健康与否)后,服务结束发起服务注册有两种方式,⼀种是直接创建服务,⼀种是注册实例时自动创建服务;前者可以让发起者在创 建时期就制定⼀部分服务的元数据信息,而后者只会使用默认的元数据创建服务生命周期
-
- 实例生命周期
实例的生命周期开始于注册实例的请求。但是根据不同的持久化属性,实例后续的生命周期有⼀定的不同
持久化的实例,会通过健康检查的状态维护健康状态,但是不会自动的终止该实例的生命周期;在生命周期 结束之前,持久化实例均可以被修改数据,甚至主动修改其健康状态。唯⼀终止持久化实例生命周期的方式 就是注销实例的请求
非持久化的实例,会根据版本的不同,采用不同的方式维持健康状态:如果是 Nacos1.0 的版本,会通过定时的心跳请求来进行续约,当超过⼀定时间内没有心跳进行续约时,该非持久化实例则终止生命周期;如果是 Nacos2.0 的版本,会通过 gRPC 的长连接来维持状态,当连接发生中断时,该非持久化实例则终止生命周期。 - 实例生命周期
3.集群生命周期
集群作为服务和实例的⼀个中间层,因此集群的生命周期与实例和服务的生命周期均有关,集群的生命周期开始与该集群第⼀个实例的生命周期同时开始,到集群下最后一个服务生命周期结束4.元数据生命周期
元数据的其对应的数据模型是紧密关联的,所以元数据的生命周期基本和对应的数据模型保持⼀致,因为元数据通常为运维人员的主动操作的数据,会被 Nacos 进行⼀段时间内的记忆,因此元数据的生命周期的终止相比对应的数据要滞后;若这滞后期间内,对应的数据又重新开始生命周期,则该元数据的生命周期将被立刻重置,不再终止
4.Nacos健康检查机制
注册中心不应该仅仅提供服务注册和发现功能,还应该保证对服务可用性进行监测,对不健康的服务和过期的进行标识或剔除,维护实例的生命周期,以保证客户端尽可能的查询到可用的服务列表。
4.1 注册中心的健康检查机制
注册中心健康检查机制分两种
- 1.服务主动上报
- 2.注册中心主动向下探测
在当前主流的注册中心,对于健康检查机制主要都采用了 TTL(Time To Live)机制,即客户端在⼀定时间没有向注册中心发送心跳,那么注册中心会认为此服务不健康,进而触发后续的剔除逻辑
两种机制使用场景不同
4.2 Nacos健康检查机制
临时实例只是临时存在于注册中心中,会在服务下线或不可用时被注册中心剔除,临时实例会与注册中心保持心跳,注册中心会在⼀段时间没有收到来自客户端的心跳后会将实例设置为不健康,然后在⼀段时间后进行剔除。永久实例在被删除之前会永久的存在于注册中心,且有可能并不知道注册中心存在,不会主动向注册中心上报心跳,那么这个时候就需要注册中心主动进行探活。
4.2.1 临时实例健康检查机制
在 Nacos 中,用户可以通过两种方式进行临时实例的注册,通过 Nacos 的 OpenAPI 进行服务注册或通过 Nacos 提供的 SDK 进行服务注册
OpenAPI 通过 Http 接口发送心跳到注册中心。在注册服务的同时会注册⼀个全局的客户端心跳检测的任务。在服务⼀段时间没有收到来自客户端的心跳后,该任务会将其标记为不健康,如果在间隔的时间内还未收到心跳,那么该任务会将其剔除。
SDK 的注册方式实际是通过 RPC 与注册中心保持连接(Nacos 2.x 版本中,旧版的还是仍然通过OpenAPI 的方式),客户端会定时的通过 RPC 连接向 Nacos 注册中心发送心跳,保持连接的存活。如果客户端和注册中心的连接断开,那么注册中心会主动剔除该 client 所注册的服务,达到下线的效果。同时 Nacos 注册中心还会在注册中心启动时,注册⼀个过期客户端清除的定时任务,用于删除那些健康状态超过⼀段时间的客户端
4.2.2 永久实例健康检查机制
Nacos 中使用 SDK 对于永久实例的注册实际也是使用 OpenAPI 的方式进行注册,这样可以保证即使是客户端下线后也不会影响永久实例的健康检查。
对于永久实例的的监看检查,Nacos 采用的是注册中心探测机制,注册中心会在永久服务初始化时根据客户端选择的协议类型注册探活的定时任务。Nacos 现在内置提供了三种探测的协议,即Http、TCP 以及 MySQL 。⼀般而言 Http 和 TCP 已经可以涵盖绝大多数的健康检查场景。MySQL 主要用于特殊的业务场景,例如数据库的主备需要通过服务名对外提供访问,需要确定当前访问数据库是否为主库时,那么我们此时的健康检查接口,是⼀个检查数据库是否为主库的 MySQL命令。
Nacos 提供了对应的白名单配置,用户可以将服务配置到该白名单,那么Nacos 会放弃对其进行健康检查,实例的健康状态也始终为用户传入的健康状态
4.2.3 集群模式下的健康检查机制
对于集群下的服务,Nacos ⼀个服务只会被 Nacos 集群中的⼀个注册中心所负责,其余节点的服务信息只是集群副本,用于订阅者在查询服务列表时,始终可以获取到全部的服务列表。临时实例只会对其被负责的注册中心节点发送心跳信息,注册中心服务节点会对其负责的永久实例进行健康探测,在获取到健康状态后由当前负责的注册中心节点将健康信息同步到集群中的其他的注册中心
在 Nacos 中,服务的注册我们从注册方式维度实际可以分为两大类。第⼀类通过 SDK RPC 连接进行注册,客户端会和注册中心保持链接。第二类,通过 OpenAPI 进行 IP 和端口注册。
SDK RPC
服务和注册中心集群中的任意⼀台节点建立联系,那么由这个节点负责这个客户端就可以了。注册中心会在启动时注册⼀个全局的同步任务,用于将其当前负责的所有节点信息同步到集群中的其他节点,其他非负责的节点也会创建该客户端的信息,在非负责的节点上,连接类型的客户端,会有⼀个续约时间的概念,在收到其他节点的同步信息时,更新续约时间为当前时间,如果在集群中的其他节点在⼀段时间内没有收到不是自己的负责的节点的同步信息,那么认为此节点已经不健康,从而达到对不是自己负责的节点健康状态检查
OpenAPI
OpenAPI 注册的临时实例也是通过同步自身负责的节点到其他节点来更新其他节点的对应的临时实例的心跳时间,保证其他节点不会删除或者修改此实例的健康状态。
4.Nacos配置管理模块
配置一致性模型
Nacos 配置管理⼀致性协议分为两个大部分,第⼀部分是 Server 间⼀致性协议,⼀个是 SDK 与Server 的⼀致性协议,配置作为分布式系统中非强⼀致数据,在出现脑裂的时候可用性高于⼀致性,因此采用 AP ⼀致性协议。
4.1 Server 间的⼀致性协议
4.1.1 有 DB 模式(读写分离架构)
⼀致性的核心是 Server 与 DB 保持数据⼀致性,从而保证 Server 数据⼀致;Server 之间都是对等的。数据写任何⼀个 Server,优先持久化,持久化成功后异步通知其他节点到数据库中拉取最新配置值,并且通知写入成功
4.1.2 无 DB 模式
Server 间采用 Raft 协议保证数据一致性
4.2 SDK 与 Server 的⼀致性协议
SDK 与 Server ⼀致性协议的核心是通过 MD5 值是否⼀致,如果不⼀致就拉取最新值。
Nacos 1.x
Nacos 1.X 采用 Http 1.1 短链接模拟长链接,每 30s 发⼀个心跳跟 Server 对比 SDK 配置 MD5 值是否跟 Server 保持⼀致,如果⼀致就 hold 住链接,如果有不⼀致配置,就把不⼀致的配置返回,然后 SDK 获取最新配置值。
Nacos 2.X
Nacos 2.x 相比上面 30s ⼀次的长轮训,升级成长链接模式,配置变更,启动建立长链接,配置变更服务端推送变更配置列表,然后 SDK 拉取配置更新,因此通信效率大幅提升。