一、引言
在上一章节当中,我们讲解了在Nacos 集群下,集群心跳健康检查定时任务是只会有一个实例去执行的。然后还讲解了怎么把结果同步给其他集群实例的。
本章我们来讲解下Nacos集群下,新增服务实例是怎么同步给其他集群节点的 ?
本章重点
- 在客户端发起实例注册请求后,注册请求成功后,Nacos服务端是怎么同步给其他集群节点的 ?
二、目录
目录
三、新增实例同步集群节点源码架构分析
首先 Nacos 在 1.4.1 这个版本中,这一块源码,Nacos 是利用 双层内存队列 + 异步任务 来实现的~
第一层:第一层是利用了 ConcurrentHashMap 作为任务储存容器,把Nacos 新增的节点信息包装成 DistroDelayTask 类型任务丢入到 ConcurrentHashMap 当中,然后在DistroTaskEngineHioldet 类中会去创建 DistroDelayTaskExecuteEngine 对象,在 DistroDelayTaskExecuteEngine 对象当中会去调用父类的构造方法,开启延时任务,从而去 ConcurrentHashMap 当去取任务,然后放入到第二层队列当中。
第二层:第二层是利用了 BlockingQueue 作为任务储存容器,第二层接受到第一层的 task 任务,会去先包装成 DistroSyncChangeTask 类型任务,然后放入到阻塞队列 BlockingQueue 当中。在 InnerWorker 中, 会从 BlockingQueue 队列当中获取任务,然后调用 DistroSyncChangeTask 当中的 run 方法。
最后在这个 run 方法当中会去发送HTTP 请求,同步给其他集群节点新增实例信息!
四、新增实例同步集群节点源码分析
那我们接着从第二章客户端发送注册请求,接着讲起。在 DistroConsistencyServiceImpl 类中的 put 方法:
@Override
public void put(String key, Record value) throws NacosException {
// 实例注册请求,封装任务丢入到阻塞队列中
onPut(key, value);
// 本章重点:实例注册请求进行集群节点同步
distroProtocol.sync(new DistroKey(key, KeyBuilder.INSTANCE_LIST_KEY_PREFIX), DataOperation.CHANGE,
globalConfig.getTaskDispatchPeriod() / 2);
}
第一层:内存队列 + 异步任务
我们之前在第二章只讲了 onPut(key, value); 方法中实例注册请求的代码,没有讲解 实例注册请求成功后,怎么同步给其他集群节点的,那我们本章就开始讲解distroProtocol.sync 这个方法:
这里 memberManager.allMembersWithoutSelf() 当中获取的集群信息,是从cluster.conf 文件当中读取的。
这里为什么要 遍历除开自身以外的所有集群节点 ? 是因为本身的节点是不需要数据同步,只需要同步给其他集群节点即可。
然后封装两层,调用 distroTaskEngineHolder.getDelayTaskExecuteEngine().addTask() 方法。
public void sync(DistroKey distroKey, DataOperation action, long delay) {
// 遍历除开自身以外的所有集群节点
for (Member each : memberManager.allMembersWithoutSelf()) {
// 包装第一层
DistroKey distroKeyWithTarget = new DistroKey(distroKey.getResourceKey(), distroKey.getResourceType(),
each.getAddress());
// 包装第二层
DistroDelayTask distroDelayTask = new DistroDelayTask(distroKeyWithTarget, action, delay);
// 把新增节点信息包装成 task任务
distroTaskEngineHolder.getDelayTaskExecuteEngine().addTask(distroKeyWithTarget, distroDelayTask);
if (Loggers.DISTRO.isDebugEnabled()) {