Nacos 作为一个分布式服务发现与配置管理平台,支持 多数据中心(Multi-DC)部署。在跨地域、跨集群的场景下,如何实现 集群间的数据同步 是关键问题。
为此,Nacos 提供了官方的数据同步工具 —— Nacos Sync(也称 Nacos-Sync 或 nacos-sync),它是一个独立的开源项目(github.com/nacos-group/nacos-sync),用于实现 多个 Nacos 集群之间的服务与配置数据双向/单向同步。
本文将从 源码角度 深入解析 Nacos Sync 的核心架构与实现机制,涵盖:
- 整体架构设计
- 数据同步流程
- 服务发现同步源码分析
- 配置数据同步源码分析
- 调度与心跳机制
- 失败重试与一致性保障
📌 注:Nacos Sync 是一个独立于 Nacos 主体的中间件,不内置在 Nacos Server 中。
一、Nacos Sync 简介
1. 核心功能
- 支持 Nacos 到 Nacos 的服务与配置同步
- 支持 Eureka、ZooKeeper、Consul 到 Nacos 的桥接(但本文聚焦 Nacos ↔ Nacos)
- 支持单向/双向同步
- 提供 Web 控制台管理同步任务
- 支持增量同步 + 全量同步
2. 典型使用场景
北京集群 ←→ 上海集群(双活)
杭州集群 → 北京集群(灾备)
二、整体架构图
+------------------+ +------------------+
| Nacos Cluster A |<----> Nacos Sync App <---->| Nacos Cluster B |
+------------------+ +------------------+ +------------------+
↑ ↑ ↑ ↑ ↑
服务注册 配置发布 同步任务调度 服务发现 配置获取
- Nacos Sync App 是一个独立的 Spring Boot 应用。
- 它作为“客户端”同时连接两个 Nacos 集群,监听变更并转发。
三、核心模块与源码结构(GitHub 项目)
项目地址:https://github.com/nacos-group/nacos-sync
关键模块:
nacos-sync/
├── nacos-sync-core/ // 核心同步逻辑
├── nacos-sync-dao/ // 数据库存储(MySQL)
├── nacos-sync-web/ // Web 控制台
├── nacos-sync-worker/ // 同步执行器
└── nacos-sync-api/ // 对接 Nacos SDK
四、数据同步流程总览
1. 用户在 Web 控制台创建同步任务(源集群 → 目标集群)
2. 任务持久化到 MySQL
3. 调度器加载任务并启动 SyncWorker
4. SyncWorker 使用 Nacos SDK 订阅源集群的服务/配置变更
5. 变更事件触发后,调用目标集群的 API 写入数据
6. 记录同步状态(成功/失败)
7. 失败则加入重试队列
五、服务同步源码详解(Service Sync)
1. 创建同步任务:SyncServiceController
// com.nacossync.controller.SyncServiceController
@PostMapping("/add")
public ResponseDto addSyncTask(@RequestBody SyncTaskDTO taskDTO) {
syncTaskService.add(taskDTO);
return ResponseDto.success();
}
SyncTaskDTO包含:sourceClusterId,destClusterIddataId,group,namespace(配置)serviceName,groupName(服务)syncMode(单向/双向)
2. 任务调度:ScheduleTask
// com.nacossync.schedule.ScheduleTask
@Component
public class ScheduleTask {
@Scheduled(fixedDelay = 10_000)
public void loadAndScheduleTasks() {
List<SyncTaskDO> tasks = syncTaskDAO.selectEnableTasks();
for (SyncTaskDO task : tasks) {
if (!syncWorkerManager.isRunning(task.getTaskId())) {
syncWorkerManager.start(task);
}
}
}
}
- 每 10 秒扫描一次数据库中的启用任务。
- 通过
syncWorkerManager.start(task)启动同步工作线程。
3. 启动服务同步:ServiceSyncWorker
// com.nacossync.worker.impl.ServiceSyncWorker
public class ServiceSyncWorker implements SyncWorker {
private NamingService sourceNamingService; // 源集群 Nacos Client
private NamingService destNamingService; // 目标集群 Nacos Client
@Override
public void start(SyncTaskDO task) {
// 初始化两个集群的 Nacos Client
sourceNamingService = NacosFactory.createNamingService(task.getSourceClusterUrl());
destNamingService = NacosFactory.createNamingService(task.getDestClusterUrl());
// 订阅源集群服务变更
sourceNamingService.subscribe(task.getServiceName(), task.getGroupName(), event -> {
if (event instanceof InstanceChangeEvent) {
handleInstanceChange((InstanceChangeEvent) event, task);
}
});
}
}
- 使用
Nacos SDK的subscribe监听服务实例变化。 - 支持
ADDED,REMOVED,HEALTHY,UNHEALTHY事件。
4. 处理变更并同步:handleInstanceChange
private void handleInstanceChange(InstanceChangeEvent event, SyncTaskDO task) {
Instance instance = event.getInstance();
try {
switch (event.getEventType()) {
case ADDED:
case HEALTHY:
destNamingService.registerInstance(task.getServiceName(), task.getGroupName(), instance);
break;
case REMOVED:
case UNHEALTHY:
destNamingService.deregisterInstance(task.getServiceName(), task.getGroupName(), instance.getIp(), instance.getPort());
break;
}
// 更新同步状态
syncTaskDAO.updateLastSyncTime(task.getTaskId(), System.currentTimeMillis());
} catch (Exception e) {
// 记录失败,加入重试
retryManager.addRetry(new RetryTask(task, event));
Loggers.SYNC.error("Sync instance failed", e);
}
}
- 使用
registerInstance/deregisterInstance同步到目标集群。 - 异常时调用
retryManager.addRetry()。
六、配置同步源码详解(Config Sync)
1. 配置同步器:ConfigSyncWorker
// com.nacossync.worker.impl.ConfigSyncWorker
public class ConfigSyncWorker implements SyncWorker {
private ConfigService sourceConfigService;
private ConfigService destConfigService;
@Override
public void start(SyncTaskDO task) {
sourceConfigService = NacosFactory.createConfigService(task.getSourceClusterUrl());
destConfigService = NacosFactory.createConfigService(task.getDestClusterUrl());
// 获取当前配置(全量同步)
String content = sourceConfigService.getConfig(task.getDataId(), task.getGroup(), 5000);
// 推送到目标集群
destConfigService.publishConfig(task.getDataId(), task.getGroup(), content);
// 监听后续变更(增量同步)
sourceConfigService.addListener(task.getDataId(), task.getGroup(), new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
try {
destConfigService.publishConfig(task.getDataId(), task.getGroup(), configInfo);
syncTaskDAO.updateLastSyncTime(task.getTaskId(), System.currentTimeMillis());
} catch (NacosException e) {
retryManager.addRetry(new RetryTask(task, configInfo));
}
}
});
}
}
- 首次启动时执行 全量同步(
getConfig+publishConfig)。 - 之后通过
addListener实现 增量同步。
七、重试机制:RetryManager
// com.nacossync.retry.RetryManager
@Component
public class RetryManager {
private final BlockingQueue<RetryTask> retryQueue = new LinkedBlockingQueue<>();
@PostConstruct
public void init() {
// 启动重试线程
new Thread(this::retryLoop).start();
}
private void retryLoop() {
while (true) {
RetryTask task = retryQueue.take();
if (task.getRetryCount() < MAX_RETRY_TIMES) {
Thread.sleep(Math.pow(2, task.getRetryCount()) * 1000); // 指数退避
execute(task);
task.incrementRetryCount();
} else {
Loggers.SYNC.error("Retry failed after {} times: {}", MAX_RETRY_TIMES, task);
}
}
}
}
- 支持最多 3~5 次重试。
- 采用 指数退避 策略,避免雪崩。
八、数据库设计(MySQL)
CREATE TABLE sync_task (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
task_name VARCHAR(64),
source_cluster_id VARCHAR(64),
dest_cluster_id VARCHAR(64),
data_type ENUM('SERVICE', 'CONFIG'),
service_name VARCHAR(128),
group_name VARCHAR(128),
data_id VARCHAR(128),
group VARCHAR(128),
sync_mode ENUM('ONEWAY', 'BIDIRECTIONAL'),
status TINYINT DEFAULT 1,
last_sync_time BIGINT
);
- 所有同步任务持久化存储。
- 支持动态增删改查。
九、Web 控制台功能
- 任务管理:增删改查同步任务
- 同步日志:查看成功/失败记录
- 集群管理:维护 Nacos 集群地址
- 状态监控:实时显示同步延迟
十、源码调用链总结
服务同步链路:
SyncServiceController.add()
→ syncTaskDAO.insert()
→ ScheduleTask.loadAndScheduleTasks()
→ ServiceSyncWorker.start()
→ sourceNamingService.subscribe()
→ InstanceChangeEvent
→ destNamingService.registerInstance()
配置同步链路:
ConfigSyncWorker.start()
→ sourceConfigService.getConfig() → 全量同步
→ sourceConfigService.addListener() → 增量监听
→ receiveConfigInfo()
→ destConfigService.publishConfig()
十一、局限性与注意事项
| 问题 | 说明 |
|---|---|
| 不支持自动冲突解决 | 若双向同步,需避免同名服务/配置冲突 |
| 无最终一致性保证 | 依赖重试,极端情况下可能丢失变更 |
| 性能瓶颈在单节点 | Sync App 是单点,高并发需集群化部署 |
| 不支持批量同步 | 每个任务独立运行,资源消耗大 |
十二、总结
| 特性 | 实现方式 |
|---|---|
| 同步模式 | 基于 Nacos SDK 订阅 + 调用 API 写入 |
| 服务同步 | subscribe + registerInstance |
| 配置同步 | getConfig + addListener + publishConfig |
| 调度机制 | 定时扫描数据库任务 |
| 可靠性 | 重试 + 日志记录 |
| 存储 | MySQL 持久化任务 |
建议阅读源码路径
ServiceSyncWorker.java—— 服务同步核心ConfigSyncWorker.java—— 配置同步核心ScheduleTask.java—— 任务调度RetryManager.java—— 重试机制sync_task表结构 —— 任务持久化
1689

被折叠的 条评论
为什么被折叠?



