图文解析 Nacos 配置中心的实现

news2024/11/24 12:37:56

目录

一、什么是 Nacos

二、配置中心的架构

三、Nacos 使用示例

(一)官方代码示例

(二)Properties 解读

(三)配置项的层级设计

(四)获取配置

(五)注册监听器

(六)配置长轮询

四、Nacos 服务端解析

(一)配置 Dump

(二)配置注册

(三)处理长轮询

五、全文总结


一、什么是 Nacos

Nacos 是阿里发起的开源项目,地址:github.com/alibaba/nac…。Nacos 主要提供两种服务,一是配置中心,支持配置注册、变更下发、层级管理等,意义是不停机就可以动态刷新服务内部的配置项;二是作为命名服务,提供服务的注册和发现功能,通常用于在 RPC 框架的 ClientServer 中间充当媒介,还附带有健康监测、负载均衡等功能。

本文聚焦于 Nacos 的第一块功能,即配置中心的实现。先叙述一个配置中心通常需要哪些组成部分,再结合 Nacos 1.1.4 的源码,探究一下这些设计是如何反映在源码上的。

二、配置中心的架构

配置中心本身并不复杂,前提是你先将 CAP 的取舍问题晾在一边的话。配置中心最基础的功能就是存储一个键值对,用户发布一个配置(configKey),然后客户端获取这个配置项(configValue);进阶的功能就是当某个配置项发生变更时,将变更告知客户端刷新旧值。

下方的架构图,简要描述了一个配置中心的大致架构,用户可以通过管理平台发布配置,通过 HTTP 调用将配置注册到服务端,服务端将之保存在 MySQL 等持久化存储引擎中;用户通过客户端 SDK 访问服务端的配置,同时建立 HTTP 的长轮询监听配置项变更,同时为了减轻服务端压力和保证容灾特性,配置项拉取到客户端之后会保存一份快照在本地文件中,SDK 优先读取文件里的内容。

这里省略了许多细节问题,例如配置分层设计,权限校验,客户端长轮询的间隔设置,服务端每次查询都需要访问 MySQL 么,配置变更是主动推送还是等定时轮询触发等,还有就是运维高可用方面的工作(私以为这个是配置中心的精华),例如节点跨地域部署,网络分区时配置如何保证可写可推送变更等。真正实现一个高质量的配置中心,还是需要长时间打磨的。

undefined

三、Nacos 使用示例

下文涉及的源码均基于 Nacos 1.1.4 版本

(一)官方代码示例

先看一下官方文档中对于 NacosAPI 使用的示例代码,第一步是传递配置,新建 ConfigService 实例,第二步可以通过相应的接口获取配置和注册配置监听器。使用方式非常简单易懂,不再赘述。

try {
    // 传递配置
	String serverAddr = "{serverAddr}";
	String dataId = "{dataId}";
	String group = "{group}";
	Properties properties = new Properties();
	properties.put("serverAddr", serverAddr);
    
    // 新建 configService
	ConfigService configService = NacosFactory.createConfigService(properties);
	String content = configService.getConfig(dataId, group, 5000);
	System.out.println(content);
    
    // 注册监听器
    configService.addListener(dataId, group, new Listener() {
	@Override
	public void receiveConfigInfo(String configInfo) {
		System.out.println("recieve1:" + configInfo);
	}
	@Override
	public Executor getExecutor() {
		return null;
	}
});
} catch (NacosException e) {
    // TODO 
    -generated catch block
    e.printStackTrace();
}

(二)Properties 解读

serverAddr 传递的是配置中心服务端的地址列表,被内部名为 ServerListManager 的类解析成地址列表进行管理,进行 HTTP 调用时会从中选择存活的机器拼接成 URL 完成调用,一旦在调用时该地址抛异常,则客户端会有一些处理措施,例如转换下次选择的节点等。值得注意的是,通常在实践中不会采取这种硬编码的方式,可以将其配置在 Zookeeper 或者注册发现中心上,在启动时动态拉取。

(三)配置项的层级设计

Nacos 官方给出了这样的设计图:

undefined

dataId 可以理解为用户自定义的配置健,group 可以理解为配置分组名称,这个属于配置层级设计的概念。简单来说,配置中心会通过层次设计,来支持不同的分区,以此区分不同的环境、不同的分组、甚至不同的开发者,满足在开发过程中灰度发布、测试等需求。因此怎样设计都可以,只要有含义就好,例如下图也不是不可以。

undefined

Nacos 客户端解析

(四)获取配置

获取配置的主要方法是 NacosConfigService 类的 getConfigInner 方法,通常情况下该方法直接从本地文件中取得配置的值,如果本地文件不存在或者内容为空,则再通过 HTTP GET 方法从远端拉取配置,并保存到本地快照中。

undefined

当通过 HTTP 获取远端配置时,Nacos 提供了两种熔断策略,一是超时时间,二是最大重试次数,默认重试三次。

(五)注册监听器

配置中心客户端对某个配置项注册监听器是很常见的需求,达到在配置项变更的时候执行回调的功能。

iconfig.addListener(dataId, group, ml);
iconfig.getConfigAndSignListener(dataId, group, 1000, ml);

Nacos 可以通过以上方式注册监听器,它们内部的实现均是调用 ClientWorker 类的 addCacheDataIfAbsent。其中 CacheData 是一个维护配置项和其下注册的所有监听器的实例,私以为这个名字取得并不好,不容易理解。

所有的 CacheData 都保存在 ClientWorker 类中的原子 cacheMap 中,其内部的核心成员有:

undefined

其中,content 是配置内容,MD5 值是用来检测配置是否发生变更的关键,内部还维护着一个若干监听器组成的数组,一旦发生变更则依次回调这些监听器。

(六)配置长轮询

ClientWorker 通过其下的两个线程池完成配置长轮询的工作,一个是单线程的 executor,每隔 10ms 按照每 3000 个配置项为一批次捞取待轮询的 cacheData 实例,将其包装成为一个 LongPollingTask 提交进入第二个线程池 executorService 处理。

undefined

该长轮询任务内部主要分为四步:

  1. 检查本地配置,忽略本地快照不存在的配置项,检查是否存在需要回调监听器的配置项
  2. 如果本地没有配置项的,从服务端拿,返回配置内容发生变更的键值列表
  3. 每个键值再到服务端获取最新配置,更新本地快照,补全之前缺失的配置
  4. 检查 MD5 标签是否一致,不一致需要回调监听器

如果该轮询任务抛出异常,等待一段时间再开始下一次调用,减轻服务端压力。另外,NacosHTTP 工具类中也有限流器的代码,通过多种手段降低轮询或者大流量情况下的风险。下文还会讲到,如果在服务端没有发现变更的键值,那么服务端会夯住这个 HTTP 请求一段时间(客户端侧默认传递的超时是 30s),以此进一步减轻客户端的轮询频率和服务端的压力。

四、Nacos 服务端解析

(一)配置 Dump

服务端启动时就会依赖 DumpServiceinit 方法,从数据库中 load 配置存储在本地磁盘上,并将一些重要的元信息例如 MD5 值缓存在内存中。服务端会根据心跳文件中保存的最后一次心跳时间,来判断到底是从数据库 dump 全量配置数据还是部分增量配置数据(如果机器上次心跳间隔是 6h 以内的话)。

全量 dump 当然先清空磁盘缓存,然后根据主键 ID 每次捞取一千条配置刷进磁盘和内存。增量 dump 就是捞取最近六小时的新增配置(包括更新的和删除的),先按照这批数据刷新一遍内存和文件,再根据内存里所有的数据全量去比对一遍数据库,如果有改变的再同步一次,相比于全量 dump 的话会减少一定的数据库 IO 和磁盘 IO 次数。

(二)配置注册

Nacos 服务端是一个 SpringBoot 实现的服务,注册配置主要代码位于 ConfigControllerConfigServletInner 中。服务端一般是多节点部署的集群,因此请求一开始只会打到一台机器,这台机器将配置插入 MySQL 中进行持久化,这部分代码很简单不再赘述。

因为服务端并不是针对每次配置查询都去访问 MySQL 的,而是会依赖 dump 功能在本地文件中将配置缓存起来。因此当单台机器保存完毕配置之后,需要通知其他机器刷新内存和本地磁盘中的文件内容,因此它会发布一个名为 ConfigDataChangeEvent 的事件,这个事件会通过 HTTP 调用通知所有集群节点(包括自身),触发本地文件和内存的刷新。

undefined

(三)处理长轮询

上文提到,客户端会有一个长轮询任务,拉取服务端的配置变更,那么服务端是如何处理这个长轮询任务的呢?源码逻辑位于 LongPollingService 类,其中有一个 Runnable 任务名为 ClientLongPolling,服务端会将受到的轮询请求包装成一个 ClientLongPolling 任务,该任务持有一个 AsyncContext 响应对象(Servlet 3.0 的新机制),通过定时线程池延后 29.5s 执行。

为什么比客户端 30s 的超时时间提前 500ms 返回是为了最大程度上保证客户端不会因为网络延时造成超时

undefined

这里需要注意的是,在 ClientLongPolling 任务被提交进入线程池待执行的同时,服务端也通过一个队列 allSubs 保存了所有正在被夯住的轮询请求,这是因为在配置项被夯住的期间内,如果用户通过管理平台操作了配置项变更、或者服务端该节点收到了来自其他节点的 dump 刷新通知,那么都应立即取消夯住的任务,及时通知客户端数据发生了变更。

为了达到这个目的,LongPollingService 类继承自 Event 接口,实际上本身是个事件触发器,需要实现 onEvent 方法,其事件类型是 LocalDataChangeEvent

当服务端在请求被夯住的期间接收到某项配置变更时,就会发布一个 LocalDataChangeEvent 类型的事件通知(注意同上文中的 ConfigDataChangeEvent 区别),之后会将这个变更包装成一个 DataChangeTask 异步执行,内容就是从 allSubs 中找出夯住的 ClientLongPolling 请求,写入变更强制其立即返回。

因此完整的流程如下,如果非接收请求的节点,那么忽略第一步持久化配置后开始:

undefined

五、全文总结

本文聚焦于 Nacos 作为配置中心的源码实现,包含了客户端和服务端两部分,内容基本覆盖了配置中心功能的关键点,既作为学习总结,也希望对阅读的朋友有所帮助。

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

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

相关文章

nfs配置

1.NFS介绍 NFS就是Network File System的缩写,它最大的功能就是可以通过网络,让不同的机器、不同的操 作系统可以共享彼此的文件。 NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文 件系统中,而在本地端的系统中来看&#…

【gltf-pipeline】安装gltf-pipeline 进行文件格式转换

问题 想使用gltf-pipeline进行gltf和glb格式转换。简单记录一下安装过程。 解决 1、安装Node.js Node.js下载路径:https://nodejs.org/en 建议默认设置安装。 添加系统环境变量: 测试安装是否成功: 在cmd.exe中运行: no…

基于SSM的建筑装修图纸管理平台

末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:采用JSP技术开发 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目&#x…

基于ssm的校园办公室报修管理系统

基于ssm的校园办公室报修管理系统 摘要 基于SSM的校园办公室报修管理系统是一个现代化的、高效的报修平台,它能够帮助校园内的教职工和学生更方便、更快捷地提交和处理报修请求。该系统基于Spring、SpringMVC和MyBatis(简称SSM)开发&#xff…

【MySQL】一文学会所有MySQL基础知识以及基本面试题

文章目录 前言 目录 文章目录 前言 一、主流数据库以及如何登陆数据库 二、常用命令使用 三、SQL分类 3.1 存储引擎 四、创建数据库如何设置编码等问题 4.1操纵数据库 4.2操纵表 五、数据类型 六、表的约束 七、基本查询 八、函数 九、复合查询 十、表的内连和外连 十一、索引…

第十八章Swing程序设计总结

例题18.1:第一个窗体程序 例题18.2:在窗体中弹出对话框 例题18.3:弹出会话框,问用户准备好了吗? 例题18.4:弹出会话框,询问用户是否离开 例题18.5:弹出会话框,让用户输入…

特殊矩阵的压缩存储(对称矩阵,三角矩阵,三对角矩阵,稀疏矩阵)

目录 1.数组的存储结构1.—维数组2.二维数组1.行优先存储2.列优先存储 2.特殊矩阵1.对称矩阵1.行优先存储 2.三角矩阵1.上三角矩阵2.下三角矩阵 3.三对角矩阵(带状矩阵)4.稀疏矩阵 1.数组的存储结构 1.—维数组 各数组元素大小相同,且物理上…

vue-router路由守卫进阶

vue-router路由守卫进阶 路由守卫,可以想象为古代御前侍卫,路由守卫,则是对路由进行权限控制 分类:全局守卫、独享守卫、组件内守卫 全局前置-路由守卫 作用:主要用来鉴权 用户点击导航区,随后引起路径的…

Android平台上执行C/C++可执行程序,linux系统编程开发,NDK开发前奏。

Android平台上执行C/C可执行程序,linux系统编程开发,NDK开发前奏准备。 1.下载NDK,搭建NDK开发环境 下载地址 https://developer.android.com/ndk/downloads 下载过程中点击下面箭头的地方,点击鼠标右键,复制好下载…

自动化实战 - 测试个人博客系统

前言 本篇使用Selenium3Junit5对个人博客进行自动化测试,如有错误,请在评论区指正,让我们一起交流,共同进步! 文章目录 前言一.web自动化测试用例二.测试准备1.注册界面自动化测试测试过程中遇到的Bug: 2.登录界面自动…

坐标系转换(仅作记载)

一.极坐标转换为普通坐标系 参考:极坐标方程与直角坐标方程的互化 - 知乎 (zhihu.com) 公式:(无需考虑象限引起的正负问题) 普通坐标系转换为极坐标系 参考: 极坐标怎么与直角坐标系相互转化? - 知乎 (zh…

若依 验证码出不来 Fontconfig head is null, check your fonts or fonts configuration

是因为使用的OenJDK不支持awt包下的字体 解决方法: 安装FontConfig组件即可 yum install -y fontconfig

找不到模块“./App.vue”或其相应的类型声明。ts(2307)

先看报错信息: 这是我们初始创建是就自带的,怎么会错误呢,实际上是因为未定义 .vue文件的类型,导致 ts 无法解析其类型,在env.d.ts中定义后即可解决。 对于我们初学者来说,刚刚按照视频来创建的项目怎么啥…

048-第三代软件开发-数据回放

第三代软件开发-数据回放 文章目录 第三代软件开发-数据回放项目介绍数据回放 关键字: Qt、 Qml、 Data、 play back、 数据 项目介绍 欢迎来到我们的 QML & C 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C 的…

4个杀手级Pycharm高效插件

本文将介绍4个学习Python的人都应该安装的Pycharm插件,通过这些插件提高工作效率并使Pycharm看起来更美观。 1、简介 Pycharm是Python最受欢迎的集成开发环境之一。它具有良好的代码助手、漂亮的主题和快捷方式,使编写代码变得简单快捷。 话虽如此&…

两台linux虚拟机之间实现免密登录

主要实现两台虚拟机之间的免密登录,总所周知,虚拟机之间登录使用的协议是ssh协议,端口号是 22 主机 创建对应的加密文件 [rootweb-2 ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.s…

【每日一题】逃离火灾

文章目录 Tag题目来源题目解读解题思路方法一:二分枚举空间复杂度: O ( m n ) O(mn) O(mn)。 写在最后 Tag 【二分答案】【BFS】【数组】【2023-11-09】 题目来源 2258. 逃离火灾 题目解读 现在有一个人在一个二维网格的左上角,坐标 (0, 0…

2023年11月PHP测试覆盖率解决方案

【题记:最近进行了ExcelBDD PHP版的开发,查阅了大量资料,发现PHP测试覆盖率解决方案存在不同的历史版本,让我花费了蛮多时间,为了避免后人浪费时间,整理本文,而且网上没有给出Azure DevOps里面P…

GPT-4-Turbo的128K长度上下文性能如何?超过73K Tokens的数据支持依然不太好!

本文原文来自DataLearnerAI官方网站:GPT-4-Turbo的128K长度上下文性能如何?超过73K Tokens的数据支持依然不太好! | 数据学习者官方网站(Datalearner)https://www.datalearner.com/blog/1051699526438975 GPT-4 Turbo是OpenAI最新发布的号称…

MySQL:锁机制

目录 概述三种层级的锁锁相关的 SQLMyISAM引擎下的锁InnoDB引擎下的锁InnoDB下的表锁和行锁InnoDB下的共享锁和排他锁InnoDB下的意向锁InnoDB下的记录锁,间隙锁,临键锁记录锁(Record Locks)间隙锁(Gap Locks&#xff0…