Nacos源码分析-服务注册与发现(AP模式)
2023-02-28 23:39:35 3 举报
登录查看完整内容
Nacos源码分析-服务注册与发现(AP模式)
作者其他创作
大纲/内容
keys.add(key)
bind(event)
ClientBeatCheckTask
如果某个实例超过15秒秒没有收到心跳则将它健康属性设置false
retrySync(syncTask)
putServiceAndInit(service)
DistroConsistencyServiceImpl.init()
ephemeralInstances = toUpdateInstances
/raft/datum/commit
调用Server实例注销接口(HttpMethod.DELETE)
异步任务更新内存注册表
createEmptyService
服务注册
AbstractAutoServiceRegistration
1、将注册实例更新到内存注册表
ephemeralConsistencyService
如果同步不成功重试
instance.setLastBeat(System.currentTimeMillis())
getRegistration()就是NacosRegistration
循环从阻塞队列tasks里拿实例数据处理
@bean
taskScheduler.run()
将注册实例信息更新到注册表内存结构里去
同步实例信息给集群其它节点
如果缓存为空,调用Server接口,获取最新服务数据
将新注册实例加到对应服务service实例列表里去
serviceManager.removeInstance
consistencyDelegate.put()
/distro/datum
返回的就是注册时写入实例属性
mapConsistencyService(key)
将service对应的全量实例instance写入内存注册表
service.srvIPs
同步写实例数据文件
serviceRegistry就是NacosServiceRegistry实例
getServiceInfo0
/instance
从nacos官方文档上找到客户端服务发现的代码,这里先看下底层逻辑,实际上,服务发现是在第一调用服务接口时根据服务名去服务端获取的,这个参考ribbon源码
NacosServiceRegistry
调用server的实实例同步接口(HttpMethod.PUT)
服务发现
实现
否
serviceManager.registerInstance
persistentConsistencyService
往阻塞队列queue里面放入注册实例数据
raftProxy.proxyPostLarge(将注册请求转发到集群的leader节点)
register()
HttpClient.asyncHttpPostLarge
ApplicationListener
deleteIP(instance)
executor.submit(notifier)
consistencyService.onPut
阿里自己实现AP模式Distro协议
queue.offer(key)
taskDispatcher.addTask(key)
GlobalExecutor.submitTaskDispatch(taskScheduler)
putService(service)
NacosDiscoveryAutoConfiguration
如果实例不存在重新注册(如网络不通导致实例在服务端被下线或服务端重启临时实例丢失)
如果注册的实例达到一定数量就批量同步给nacos集群的其它节点,或者距离上一次节点同步达到一定时间也会开始批量同步
beatReactor.addBeatInfo
tasks.take()
源码精髓:nacos这个更新注册表内存方法里,为了防止读写并发冲突,大量的运用了CopyOnWrite思想防止并发读写冲突,具体做法就是把原内存结构复制一份,操作完最后再替换回真正的注册表内存里去。Eureka防止读写并发冲突用的方法是注册表的多级缓存结构,只读缓存,读写缓存,内存注册表,各级缓存之间定时同步,客户端感知的及时性不如nacos
serviceInfoMap(客户端实例缓存Map)
源码入口
如果是临时节点实例数据
调用Server的实例发送注册接口HttpMethod.PUT
创建内存注册表结构
if (dataSize == partitionConfig.getBatchSyncKeyCount() || (System.currentTimeMillis() - lastDispatchTime) > partitionConfig.getTaskDispatchPeriod()) {
client
instance.setHealthy(false)
InstanceController.register
发布服务变更事件
raftStore.write(datum)
queue.poll()
BeatTask
/instance/beat
NacosRegistration
if (instance.isEphemeral({添加一个延迟执行的定时心跳任务BeatTask}}
往阻塞队列task里放入注册表实例数据
2、同步实例信息到nacos server集群其它节点
allInstances.addAll(persistentInstances); allInstances.addAll(ephemeralInstances);
实现ApplicationListener接口的类Spring容器启动时会调用处理事件方法
执行实例数据批量任务同步
TaskDispatcher.init()
server
继承
onApplicationEvent
start()
如果是持久实例数据
是
NacosAutoServiceRegistration
/instance/list
NamingService.registerInstance
本节点是否leader
serverProxy.registerService
GlobalExecutor.submitDataSync
service.init()
调用Server的实例发送心跳接口HttpMethod.PUT
获取客户端的服务实例缓存信息
NacosNamingService.getAllInstances()
serviceRegistry.register(getRegistration())
调用Server的服务发现接口HttpMethod.GET
doSrvIPXT
InstanceController.list
DistroController.onSyncDatum
hostReactor.getServiceInfo
HealthCheckReactor.scheduleCheck(clientBeatCheckTask)
service.processClientBeat(clientBeat)
利用CountDownLatch实现了一个简单的raft协议写入数据的逻辑,必须集群半数以上节点写入成功才会给客户端返回成功
阿里自己实现的CP模式的简单Raft协议
如果某个实例超过30秒秒没有收到心跳,直接剔除该实例(被剔除的实例如果恢复发送心跳则会重新注册)
spring-cloud-alibaba-nacos-discovery.jar里面spring.factories文件里的EnableAutoConfiguratiod对应NacosDiscoveryAutoConfiguration
源码精髓:很多开源框架为了提升操作性能会大量使用这种异步任务操作,这些操作本身并不需要写入之后立即成功,用这种方式对提升操作性能有很大帮助
getPushService().serviceChanged(this)
notifier.run()
serverProxy.sendBeat(beatInfo)
InstanceController.beat
0 条评论
回复 删除
下一页