当前位置: 首页 > ds >正文

Nacos配置中心客户端处理服务端配置信息源码解析

文章目录

  • 前言
  • 一、服务端推送配置信息,客户端的处理
    • 1.1、客户端获取服务端请求,发布事件
    • 1.2、客户端启动时,轮询监听事件
    • 1.3、客户端订阅事件并处理
      • 1.3.1、getServerConfig远程获取配置文件
      • 1.3.2、更新文件变更checkListenerMd5
  • 总结:Nacos 配置中心客户端处理服务端推送配置信息的流程解析
      • 客户端接收服务端推送通知
      • 客户端监听线程的启动机制
      • 配置变更处理逻辑
      • 架构设计理念


前言

  Nacos配置中心,对于页面上用户操作的配置信息,实际上是使用了推拉结合的模式。

  • 服务端将配置信息推送到客户端。
  • 客户端主动向服务端发起请求拉取配置信息。

  本篇介绍服务端将配置信息推送到客户端,客户端的处理方式

一、服务端推送配置信息,客户端的处理

1.1、客户端获取服务端请求,发布事件

  当用户在页面上对配置信息进行操作时,会调用服务端ConfigControllerpublishConfig。最终还会将配置信息推送到客户端:在这里插入图片描述
  该请求会被客户端的ClientWorker.ConfigRpcTransportClient#initRpcClientHandler接收:
在这里插入图片描述
  分为了两步操作:

  1. RpcClientserverRequestHandlers集合中注册一个Handler。

在这里插入图片描述

  1. 实例化该Handler的对象,在合适的时机调用。

  在实例化ServerRequestHandler对象,重写的requestReply方法中,先是通过组合dataIdgrouptenant 生成一个唯一标识配置项的groupKey,然后去缓存中查找,如果缓存中存在对应配置:

  • 同步锁定该CacheData实例;
  • 更新最后修改时间戳;
  • 标记客户端缓存与服务端不同步;
  • 触发监听器通知。

  CacheData是Nacos客户端承载配置信息的对象,存放了基本信息:
在这里插入图片描述
  在notifyListenConfig方法中,是向listenExecutebell队列中放入了一个空的Object对象,而非具体的事件**
在这里插入图片描述
在这里插入图片描述


1.2、客户端启动时,轮询监听事件

  listenExecutebell队列中的元素何时被消费?
  在spring-cloud-starter-alibaba-nacos-config的jar包中的spring.factories文件中,有NacosConfigBootstrapConfiguration类,是Nacos配置中心启动的相关配置。
在这里插入图片描述  向Spring容器中条件装配了三个Bean。其中和本文中功能相关的,是NacosConfigManager(Nacos配置管理者)。
在这里插入图片描述
  在NacosConfigManager的构造中,实际上是要给NacosConfigManager类的两个属性赋值。

  • nacosConfigProperties代表了配置文件中的信息。
  • service是配置管理的核心接口,定义了客户端与配置中心交互的主要 API,例如获取配置、发布配置、监听配置变更等操作。这里赋值给它的是其子类NacosConfigService

在这里插入图片描述
  尝试通过反射创建NacosConfigService的实例。(通过NacosConfigService的有参构造,传入properties参数)
在这里插入图片描述
  又会去创建ClientWorker的实例:
在这里插入图片描述
  创建ClientWorker的实例的关键代码:

  • 实例化了ConfigRpcTransportClient,它是ClientWorker的一个内部类。
  • 调用ConfigRpcTransportClientstart方法。

在这里插入图片描述
  start方法,最终会调用到ConfigRpcTransportClientstartInternal,同样是在线程池中开启了一个死循环,当线程池存活时,就会一直执行里面的逻辑。**这里的listenExecutebell就是notifyListenConfig方法中放入事件的那个阻塞队列,每隔5s从队列中获取元素,获取不到就会陷入阻塞。
   这里获取到的不是具体的事件,而是一个空的Object对象。这个 Object 实际是一个“唤醒标记”,而不是用来传递事件数据的。(设计精髓)
在这里插入图片描述


上面的NacosConfigBootstrapConfiguration类。是在SpringBoot整合了Nacos,启动时利用自动配置机制完成的。所以这一块的设计和Nacos注册中心服务端获取客户端的注册信息、以及配置中心服务端消费者消费事件,向客户端发送通知 这两者的设计,是同样的道理。都是在程序启动的过程中,先初始化一个线程去轮询监听 + 阻塞队列。在相应的请求到达时,从队列中获取元素进行处理。

1.3、客户端订阅事件并处理

  当从listenExecutebell中获取到标记后,就会进入executeConfigListen的逻辑,真正地去进行事件的处理,关键代码在于refreshContentAndCheck
在这里插入图片描述
  在该方法中,首先会从缓存配置信息的Map中,获取该groupKey对应的缓存信息,然后再次调用重载的refreshContentAndCheck

  1. 远程获取配置文件
  2. 对有变化的配置调用对应的监听器去处理

在这里插入图片描述

1.3.1、getServerConfig远程获取配置文件

  最终调用到的是queryConfig方法:

  1. 又会去向服务端发送请求,获取最新的配置。
  2. 保存到本地(快照)。
    在这里插入图片描述

  服务端接收该请求的是ConfigQueryRequestHandlerhandle方法:
在这里插入图片描述
  最终是从磁盘获取的配置文件,然后响应给客户端的,所以直接改数据库中的配置信息,客户端是感知不到的。
在这里插入图片描述

这里为什么要从磁盘获取?服务端不是保存了一份到数据库中吗?
可能是考虑到性能问题,从磁盘获取文件的效率,要高于数据库的IO操作(省去了连接,响应的时间)。

1.3.2、更新文件变更checkListenerMd5

在这里插入图片描述
  最终会来到safeNotifyListener,在其中,有两处关键的代码:
  利用线程池提交一个job
在这里插入图片描述
  job中利用listenerreceiveConfigInfo方法,真正地执行逻辑
在这里插入图片描述
  选择AbstractSharedListener的实现:
在这里插入图片描述

在这里插入图片描述
  实际调用的是子类NacosContextRefresher重写的innerReceive方法:

  1. 添加一条配置信息的历史记录(在本地记录一个配置变更历史,并控制记录列表的大小不超过阈值。)
  2. 发布配置信息的刷新事件,对应的监听器是RefreshEventListener

在这里插入图片描述

这里向客户端的内存中保存了一份,如何保证和数据库中历史记录的一致性?
客户端历史记录仅用于本地用途,不参与服务端页面上的历史记录,页面展示的历史记录来源于服务端数据库;

  刷新事件与Nacos的动态刷新配置有关。

总结:Nacos 配置中心客户端处理服务端推送配置信息的流程解析

  在 Nacos 配置中心中,服务端在检测到配置内容发生变更后,会客户端推送变更通知。客户端收到推送通知,并不会直接处理变更配置内容,而是通过一系列异步机制完成完整的配置拉取与刷新流程。


客户端接收服务端推送通知

  当服务端发起配置变更的推送请求时,客户端内部的 ClientWorker.ConfigRpcTransportClient#initRpcClientHandler 会接收到该请求。客户端在接收到该通知后,并不会立即处理配置内容,而是向内部的阻塞队列 listenExecutebell 中放入一个空的 Object 实例,作为“配置已变更”的标记。

  这一设计的核心在于将处理逻辑解耦:推送通知的接收与配置内容的处理并不在同一线程中完成,而是通过队列和监听线程实现异步化与任务排队。


客户端监听线程的启动机制

  在客户端启动过程中,Nacos 通过 Spring Boot 的自动配置机制,在 NacosConfigBootstrapConfiguration 中初始化配置环境。该类会创建用于监听配置变化的线程池,启动监听任务。

  该监听线程会轮询检查 listenExecutebell 队列,一旦检测到有新元素被放入(即接收到变更标记),便开始配置处理流程。


配置变更处理逻辑

  监听线程在检测到配置变更标记后,分两个步骤完成处理:

  1. 远程拉取最新配置内容并保存快照
    客户端会通过远程调用向服务端发起配置查询请求,对应服务端处理类为 ConfigQueryRequestHandler#handle。服务端接收到请求后,会从磁盘读取对应的配置信息,并将结果返回给客户端。客户端收到后,会将配置内容写入本地快照中,用于容灾和本地缓存读取。
  2. 比对并触发配置变更事件
    客户端计算拉取到的配置内容的 MD5,与缓存中的 MD5 进行比对。如果内容发生变化,则会:
    • 记录一条配置变更历史(仅保存在客户端内存中);
    • 触发配置刷新事件,发布到 Spring 上下文中,由 RefreshEventListener 等监听器进行处理。

  需要注意的是:客户端本地记录的配置历史仅供本地诊断与调试使用,不会同步到服务端,也不参与页面展示的历史版本信息。Nacos 控制台页面中展示的历史记录,来源于服务端数据库的 his_config_info 表,由服务端在每次配置发布时自动写入。


架构设计理念

  这种设计体现了 Nacos 配置中心架构的核心理念:事件驱动 + 队列解耦 + 监听异步处理。同时体现 轻推重拉(轻量推送、客户端主动拉取) 的策略

  服务端推送的不是配置内容,而是变更事件。这个事件就是一个带有定位信息的“标记”,客户端基于这个事件再去主动获取配置内容,实现了高效、实时、低耦合的配置同步机制。客户端并不会直接处理服务端推送的配置信息,而是通过监听线程加阻塞队列的方式,将推送转化为本地的“变更信号”,再由客户端主动拉取配置、判断差异、触发刷新事件。

字段说明
dataId变更的配置项 ID
group配置所属的分组
tenant租户信息(多租户场景)

  这种机制与 Nacos 注册中心中的客户端注册/订阅模型具有高度相似性:

  • 程序启动时初始化监听线程;
  • 使用阻塞队列作为“信号触发器”;
  • 接收到变更后进行数据拉取和后续处理。

  • 客户端不会直接使用服务端推送的配置内容,而是收到通知后主动发起查询;
  • 推送仅作为“配置已变更”的标记,通过阻塞队列传递到监听线程;
  • 监听线程完成实际配置拉取、MD5 校验、历史记录记录以及刷新事件发布;
  • 客户端历史记录仅用于本地用途,控制台页面展示的历史版本来源于服务端数据库;
  • 整体设计体现了事件驱动、异步解耦的系统架构思想。
http://www.xdnf.cn/news/608.html

相关文章:

  • 透视部分国产碳化硅(SiC)MOSFET栅氧可靠性报告造假乱象
  • ClickHouse核心架构设计
  • 【中间件】redis使用
  • Gen - CDPT举例说明:动态上下文前缀(输入先和标签结合,输出结果会更贴近标签内容)
  • 大数据可能出现的bug之flume
  • Matlab 汽车行驶速度PID控制系统仿真
  • GIS开发笔记(9)结合osg及osgEarth实现三维球经纬网格绘制及显隐
  • 利用 HEMT 和 PHEMT 改善无线通信电路中的增益、速度和噪声
  • 常见的页面报错
  • 热门算法面试题第19天|Leetcode39. 组合总和40.组合总和II131.分割回文串
  • windows docker desktop 无法访问容器端口映射
  • 大模型面经 | 介绍一下CLIP和BLIP
  • mac监控linux上mysql性能(Grafana+Prometheus+mysqld_exporter)
  • 每日一题——最小测试用例集覆盖问题
  • 通过爬虫方式实现头条号发布视频(2025年4月)
  • 2025 UCSCCTF Pwn-wp(含附件)
  • Java链表反转方法详解
  • 2. 什么是最普通的自动化“裸奔状态”?
  • 扣子智能体1:创建Agent与写好提示词
  • 深入理解Linux中的线程控制:多线程编程的实战技巧
  • 【失败总结】Win10系统安装docker
  • C++ MySQL数据库访问工具类设计与操作流程详解
  • 实现AWS Data Pipeline安全地请求企业内部API返回数据
  • 学习笔记二十——Rust trait
  • 网络基础(协议,地址,OSI模型、Socket编程......)
  • C++ 多态
  • 支持向量机(SVM):原理、应用与深入解析
  • 【今日三题】判断是不是平衡二叉树(递归) / 最大子矩阵(二维前缀和) / 小葱的01串(滑动窗口)
  • Linux进程地址空间、写时拷贝
  • Java—— 常见API介绍 第一期