Nacos配置中心服务端源码解析
文章目录
概述
Nacos除了可以实现服务的注册与发现,还具有统一进行配置管理的作用,只需要额外引入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
可以将项目中的配置文件,转移到配置中心:

同时需要在项目的resource目录下,加入bootstrap.yml或bootstrap.properties文件,目的是为了在Spring Boot启动的过程中先加载注册中心地址等基础配置项:
spring:
application:
name: spring-cloud-nacos-config-demo #微服务名称
# profiles:
# active: dev #加载开发环境的配置文件 mall-user-config-demo-dev.yml
cloud:
nacos:
config: #配置nacos配置中心地址
server-addr: 192.168.101.1:8848
username: nacos
password: nacos
file-extension: yml # 指定配置文件的扩展名为yml
#namespace:
# 自定义 Data Id 的配置
shared-configs: #不同工程的通用配置 支持共享的 DataId
- data-id: common.yml
group: DEFAULT_GROUP
refresh: true
# - data-id: openfeign.yml
# group: GLOBALE_GROUP
# refresh: true #支持动态刷新
#
# extension-configs: # 支持一个应用多个 DataId 的配置
# - data-id: actuator.yml
# - data-id: common.yml
# group: REFRESH_GROUP
# refresh: true #支持动态刷新
在配置中心的页面上,新增或修改配置,实际调用的是/nacos/v1/cs/configs。

对应的是Nacos 服务端 源码中的ConfigController的publishConfig方法,在该方法中,主要完成了两件事:
- 将配置持久化到数据库。
- 发布
ConfigDataChangeEvent事件,让客户端能感知配置更新。

一、配置持久化到数据库
将配置持久化到数据库,实际调用的是ExternalStoragePersistServiceImpl#insertOrUpdate方法,整体的逻辑是,先执行新增 操作,如果抛出了DataIntegrityViolationException(数据完整性违规)异常,则会改为执行 更新 操作。
DataIntegrityViolationException 是 Spring 框架中定义的异常。这个异常表示违反了数据库的完整性约束。例如唯一性约束、非空约束、外键约束等。

使用编程式事务执行数据库的新增或修改操作:

底层使用的原生JDBC:

二、发布事件
在将页面上的数据保存到数据库中后,就会发布一个ConfigDataChangeEvent事件。

调用的是NotifyCente的publishEvent。NotifyCenter 是 Nacos 内置的异步事件总线,用于模块间解耦地传递和响应事件,是支撑配置推送、服务变更通知的关键机制,内部主要实现了:
- 事件注册:订阅你感兴趣的事件类型
- 事件发布:将事件投递出去
- 事件处理:触发订阅者的回调处理逻辑
2.1、事件发布者端
在NotifyCente的publishEvent方法中,主要完成了两件事:
- 根据eventType解析出topic,再根据topic从publisherMap属性中找到对应的发布器。
- 利用发布器将事件放入队列中。

选择DefaultPublisher的实现:

DefaultPublisher继承了Thread,该类的对象就是一个可以运行的线程。同时实现了EventPublisher接口:

EventPublisher作为Nacos事件总线发布器的顶级接口,制定了一套初始化、添加订阅者、移除订阅者、发布事件的规范。

2.1.1、DefaultPublisher#publish
在DefaultPublisher的publish方法中:
- 尝试将当前事件存放到阻塞队列中。
offer方法,在队列中元素已满的情况下,不会抛出异常,而是会返回false。 - 当队列中元素已满,则让消费者去处理当前事件。

2.1.2、DefaultPublisher#run
因为DefaultPublisher继承了Thread,所以在调用DefaultPublisher的start方法时,实际会执行run方法中的逻辑,在run方法中,完成了:
- 从队列中获取事件 (如果获取不到事件,则会在这一行陷入阻塞,不会导致cpu空转。和Nacos服务端处理客户端注册信息的设计是同样的道理)
- 通知消费者处理事件。

2.1.3、DefaultPublisher#receiveEvent
无论是run方法,还是publish方法,最终都指向了receiveEvent,在该方法中,首先会去遍历所有的订阅者,然后调用notifySubscriber方法让每一个订阅者去处理事件。

最终调用进notifySubscriber方法。会回调订阅者对象的onEvent方法去进行处理。如果订阅者配置了线程池,则还会使用线程池去处理(默认为null,没有配置)。

run方法和publish方法,最终都调用了receiveEvent,两者调用的区别在于触发时机不同:
run方法触发receiveEvent的时机,是在DefaultPublisher的start方法被调用时:

start方法又是init方法调用的。init方法的调用时机,是在NotifyCenter的静态代码块中的。伴随着NotifyCenter的加载而加载,换言之是在Nacos服务端的启动过程中,就已经调用。
publish方法则是在服务端接收到页面新增/修改配置的请求后,才会触发的。
所以run方法是先于 publish方法触发的。
2.2、事件订阅者端
2.2.1、Subscriber#onEvent
onEvent方法是在AsyncNotifyService中的逻辑,在AsyncNotifyService的构造中,首先会注册一个ConfigDataChangeEvent类型的事件,并且注册一个订阅者:

在2.3的notifySubscriber方法中,会回调onEvent方法,执行其中的逻辑:

Nacos 2.x版本中,进入的是下图的分支:

在AsyncRpcTask的run方法中,如果是当前节点,就会直接存储一份配置:

实际上也是将其加入了TaskManager的队列中,异步处理:

2.2.2、ConfigCacheService#dump
在ConfigCacheService的dump方法中,会将配置信息写入磁盘,并且配置信息发生变更时,更新文件的md5值:

还会发布一个LocalDataChangeEvent事件。注意,在ConfigController中发布的,是ConfigDataChangeEvent事件。同样是利用NotifyCenter去发布。

这个事件是被RpcConfigChangeNotifier订阅的。


在configDataChanged中,会将配置信息推送到客户端:

并且支持重试机制:

总结:Nacos 配置中心服务端事件处理机制详解
当 Nacos 作为配置中心使用时,页面端的新增或修改操作最终会通过 Controller 层发送请求到服务端。服务端接收到请求后,主要完成以下两项工作:
- 将配置信息持久化到数据库;
- 发布
ConfigDataChangeEvent事件,驱动后续变更通知流程。
其中,数据库写入过程采用编程式事务而非注解式事务,主要考虑到业务逻辑中可能存在较为复杂的数据库操作,编程式事务在控制粒度与异常处理方面更为灵活。
事件发布机制则基于 Nacos 自研的异步事件总线实现,整体设计思路与 Nacos 服务端处理客户端注册信息的机制保持一致。
服务端事件发布流程
服务端事件的发布大致可划分为两个阶段:
- 初始化阶段:服务端在启动过程中,会启动一个后台线程,进入死循环监听事件。该线程会尝试从一个阻塞队列中拉取事件:
- 如果队列为空,线程将阻塞等待,不会造成 CPU 空转;
- 一旦有事件被投递到队列中,线程会立即唤醒并执行对应的事件处理逻辑。这一机制有效地保证了资源的高效利用,也符合高并发下的异步处理模型设计。
- 运行阶段:在服务端启动完成后,当前端发起新增或修改配置的请求时,事件发布器会将
ConfigDataChangeEvent投递至上述阻塞队列,并由初始化阶段的线程消费。该线程在获取到事件后,会根据配置类型及作用域通知对应的订阅者执行后续处理逻辑。
服务端事件消费流程:
事件消费逻辑主要在订阅者侧完成,通常包括以下两步操作:
- 数据落盘:订阅者会将变更后的配置信息写入本地磁盘,同时更新其对应的 MD5 值,用于变更对比及客户端变更判断。
- 随后,订阅者会发布
LocalDataChangeEvent事件,该事件的监听器会通过 RPC 向客户端发送变更通知,提示配置已发生变更。此通知机制内置了失败重试机制,确保高可用性
事件发布与订阅关系表
| 事件类型 | 发布器 | 监听器 / 订阅者 | 功能描述 |
|---|---|---|---|
ConfigDataChangeEvent | 配置 Controller 层逻辑 | ConfigChangePublisher | 用于标记某条配置数据已变更,驱动本地磁盘写入与事件级联 |
LocalDataChangeEvent | ConfigChangePublisher | ClientRpcNotifySubscriber 等 | 通过 RPC 通知客户端配置已变更,支持失败重试,确保通知可靠性 |
设计理念回顾
Nacos 配置中心的事件驱动模型体现了以下设计理念:
- 异步解耦:通过阻塞队列与事件总线,服务端变更操作与客户端通知完全解耦,提升系统吞吐能力;
- 资源高效利用:利用阻塞机制避免线程空转,实现高效的资源调度;
- 可靠传递机制:客户端通知具备重试机制,确保在网络抖动或客户端异常的情况下,变更信息能最终送达;
- 一致性保障:通过 MD5 校验与本地磁盘备份,保障服务端与客户端配置信息的一致性。
更多推荐



所有评论(0)