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