raft竞选基本流程集群结点请求同步数据前面说了leader发送的心跳过去的时候会带有数据key的信息,其他结点可能会进行数据的同步。RaftCore的receivedBeat获取信息好长一段,其实就是根据leader带来的数据key,进行比对,要更新的就批量更新,收到后区分好Service还是InstanceList的进行更新,通知,并且更新任期状态。//不只是心跳if(!switchDomain.isSendBeatOnly()){Map<String,Integer>receivedKeysMap=newHashMap<>(datums.size());//放入所
raft竞选基本流程RaftController的beat处理心跳RaftCore的receivedBeat核心的列出来了,主要就是比对一下信息,更新本地信息。当然如果有需要同步信息的话,还要给leader发消息,获取同步的信息,我这里基本略过了,很长,有兴趣的可以细看。publicRaftPeerreceivedBeat(JSONObjectbeat)throwsException{finalRaftPeerlocal=peers.local();//本地的finalRaftPeerremote=newRaftPeer();//远程的leaderremote.ip=beat.getJSONO
raft竞选基本流程RaftCore的HeartBeat心跳我们可以看到,心跳也有超时时间,到了后重置然后发心跳。@Overridepublicvoidrun(){try{if(!peers.isReady()){return;}RaftPeerlocal=peers.local();local.heartbeatDueMs-=GlobalExecutor.TICK_PERIOD_MS;if(local.heartbeatDueMs>0){return;}//重置心跳任期local.resetHeartbeatDue();sendBeat();}catch(Exceptione){Log
raft竞选基本流程MasterElection前面说了选举测初始化,现在已经可以选举了,最开始的时候每个结点的状态都是FOLLOWER跟随者,这里就是一个开始随机时间的等待,只要开始选举了,就会等待,直到第一个任期时间到了,重置时间,为什么要重置呢,因为如果不重置的话就一直投票啦,只有当没有leader的时候或者长时间没接受到leader心跳(只有leader才会发心跳)才要投票,所以会一定时间间隔如果没有收到leader的心跳,才可能会开始投票,只要收到了,时间又会被重置,也就不需要选举leader。只要任期时间过了就开始拉票了:publicclassMasterElectionimple
选举初始化流程raft选举原理具体的raft算法原理百度下好了,很多,总的来说就是一个相对公平的能达到共识的相对好理解的一个选举算法。那么结合nacos来说下他思想是怎么体现的。具体的算法理解可以看看这个小动画,可以帮助理解,比干的文字和图片都来的好。何时开始选举我们先来搞清楚什么时候会开始选举,先看下nacos初始化服务器列表的步骤。ServerListManager的init首先是ServerListManager的初始化方法,会开启间隔5秒的ServerListUpdater任务和间隔2秒的ServerStatusReporter任务:ServerListUpdater这个任务里先会从本
nacos数据一致性服务执行流程RaftController的onPublish过半响应最终响应还是调用了RaftConsistencyServiceImpl的onPut。然后返回ok。@PostMapping("/datum/commit")publicStringonPublish(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{response.setHeader("Content-Type","application/json;charset=&
nacos数据一致性服务执行流程RaftConsistencyServiceImpl的put永久数据同步内部是调用RaftCore的signalPublish。@Overridepublicvoidput(Stringkey,Recordvalue)throwsNacosException{try{raftCore.signalPublish(key,value);}catch(Exceptione){Loggers.RAFT.error("Raftputfailed.",e);thrownewNacosException(NacosException.SERVER_ERR
nacos数据一致性服务执行流程DataStore的batchGet上篇说到要进行数据同步了,我们先来看下任务key=com.alibaba.nacos.naming.iplist.ephemeral.命名空间##分组@@服务名,所以可能队列里会有多个这样的服务名。尽管是有多个线程去队列去取,但是如果同样的key很多的话,可能一个线程会取到同样的key多个,不过没关系,后面获取数据的时候只能获取一份最新的。这里keys可能有相同的,但是dataMap里只能有一份,而且是最新的,所以不用担心。publicMap<String,Datum>batchGet(List<String
nacos数据一致性服务执行流程数据一致性其实nacos内部提供两种数据同步方案AP和CP,而且是混用的,只要你的实例是临时的默认用AP,如果是永久的要就用CP。两个数据一致性服务的处理器类结构:可以看到,左边的RaftConsistencyServiceImpl就是CP的实现类,右边的DistroConsistencyServiceImpl就是AP的实现类,我们注册实例的时候通常是DelegateConsistencyServiceImpl来帮助我们判断该用临时的还是永久的服务,其实他内部就是代理这两个:具体怎么同步的,我们先来讲AP的TaskScheduler任务同步。TaskSchedu
服务端处理查询实例列表我们看查询服务实例列表在哪里,在ZoneAwareLoadBalancer的updateListOfServers更新服务中。这里会传UDP端口,就是前篇说的服务器推送服务实例改变的时候会用到。InstanceController的list查询实例列表主要就是获取了一些信息,这里要注意udpPort,推送会用到。最后用doSrvIPXT处理,这个什么方法,好像没什么可读性啊。@GetMapping("/list")@Secured(parser=NamingResourceParser.class,action=ActionTypes.READ)pub
心跳处理基本流程ClientBeatProcessor的run处理临时实例心跳这里就体现出RsInfo的用途啦,其实就是保存下实例的相关信息,IP,端口,集群。遍历实例集群的实例,找出对应的IP和端口的实例进行状态更新。如果发现有问题,还要用PushService进行UDP进行通知,UDP端口是客户端请求的时候刷新服务实例列表的使用传上来的,客户端也有个PushReceiver就是来接受UDP报文信息,具体可以看这篇文章。@Overridepublicvoidrun(){Serviceservice=this.service;...Stringip=rsInfo.getIp();//IPStr
回顾客户端实例心跳在服务实例注册之前,如果是临时的服务实例,会先开启心跳任务,不过心跳任务5秒后会运行,第一次心跳的时候会带上心跳内容,也就是服务实例的信息,避免实例不存在又要重新注册一次:心跳处理基本流程调度心跳任务。发送心跳:uri是/nacos/v1/ns/instance/beat:如果返回找不到服务就会进行注册,所以你debug的时候可能会发现已经有注册的了,其实就是心跳去注册的。服务端处理心跳InstanceController的beat这里会接受客户端的心跳,如果是有beat信息的话,说明是第一次,会带有服务实例信息,因为如果成功了服务端会下发不要带beat信息的参数,这样客户端
Service模型大致结构DistroConsistencyServiceImpl的put临时实例集合一致性服务添加集合,然后@Overridepublicvoidput(Stringkey,Recordvalue)throwsNacosException{onPut(key,value);taskDispatcher.addTask(key);}onPut添加临时实例集合如果是临时的就添加一个Datum,将实例集合放入。如果有监听器监听的,立即通知,否则就返回,怎么通知的后面说。//临时的实例publicvoidonPut(Stringkey,Recordvalue){//如果是临时的服务实
Service模型大致结构ServiceManager的addIpAddresses上篇说到增加实例这里,看看他是怎么添加的:ServiceManager的addIpAddresses做的是一个添加的操作。publicstaticfinalStringUPDATE_INSTANCE_ACTION_ADD="add";publicList<Instance>addIpAddresses(Serviceservice,booleanephemeral,Instance...ips)throwsNacosException{returnupdateIpAddresse
客户端注册实例流程ServiceManager的putServiceAndInit继续上一篇,开始进来的时候服务为空,于是创建一个Service,设置好属性,然后进行初始化并放入映射和监听器里。我们先将临时的服务情况,也就是关闭了就没了。临时的服务实例key可能是这样com.alibaba.nacos.naming.iplist.ephemeral.public##DEFAULT_GROUP@@cloud-alibaba-provider-payment,永久的是com.alibaba.nacos.naming.iplist.public##DEFAULT_GROUP@@cloud-aliba
客户端注册实例流程注册实例官网的描述:客户端注册主要是在这个地方。服务端处理InstanceController的register方法:parseInstance解析成实例就是把传过来的参数封装成服务实例Instance。privateInstanceparseInstance(HttpServletRequestrequest)throwsException{StringserviceName=WebUtils.required(request,CommonParams.SERVICE_NAME);Stringapp=WebUtils.optional(request,"app&q
ClientLongPolling的run然后你会发现,又是一个调度任务,延迟时间29.5秒,就是最少挂起时间。然后会将对象放进监听集合里。当挂起时间过后,开始处理,因为不是固定轮询的,所以直接响应:把轮询任务给取消了,然后生成响应。如果不是固定轮询的,就直接返回了,因为在这个任务之前已经判断过没有改变,才会挂起,为了有改变的时候直接响应。如果是固定的,生成响应的时候会去比对MD5,然后把写回:监听后台配置修改LongPollingService是个监听器,他会监听配置数据改动事件。一旦有数据变动会开启一个DataChangeTask任务,里面就是做立即响应的:DataChangeTask的r
监听配置原理官网已经说了很清除了,不过我们还是看下源码,前面的客户端长轮询任务说过,会被服务器挂起,现在我们看服务器源码,看为什么会挂起,挂起当中如果有配置改变又是如何立即响应的。客户端的LongPollingRunnable这个已经讲过了,他会一直去请求监听端口,但是如果没有缓存配置是初始化的,就会被挂起,有配置修改会立即响应,否则就会立即返回。这两个头信息很关键,会影响到服务端的处理,马上就说。服务端的ConfigController的listener直接看关键的.ConfigServletInner的doPollingConfigLongPollingService的isSupportL
nacos服务端其实nacos大致功能就两个,一个是配置中心,一个是命名服务,我们先看配置中心是如何提供配置请求服务的,主要处理是在com.alibaba.nacos.config.server.controller.ConfigController中。其实很多处理请求看官方open-api就可以知道大概的原理了。获取配置ConfigController的getConfig官方API有的就不多说了,直接看源码大致原理。先获取参数,检验,通过后调用ConfigServletInner的doGetConfig方法。@GetMapping@Secured(action=ActionTypes.REA
服务获取和刷新的流程图NacosNamingService的selectInstances前面说了,负载均衡器初始化的时候会最后调用NacosNamingService的selectInstances方法,最终到这里,因为是订阅标记是true,所以直接走hostReactor.getServiceInfo,内部如果发现服务有更新会进行监听器的通知,所以叫做订阅:HostReactor的getServiceInfo先判断容灾模式,如果已经出故障了,直接从本地缓存读取。否则就尝试获取服务信息,如果没有就创建一个,然后立即去注册中心获取服务,这里用了一个updatingMap来表示再更新的服务,然后
服务获取和刷新的流程图NacosServerList实例化继续上篇,接下来就是实例化到这里了:config就是上篇最后实例化的DefaultClientConfigImpl,clientName被赋值为服务名。initWithNiwsConfig刚好可以取到:ZoneAwareLoadBalancer实例化可以看到这里注入的就是NacosServerList,因为NacosServerList实现了ServerList接口,容器里唯一一个ServerList的实例,刚好注入。然后在初始化方法restOfInit的updateListOfServers中调用的就是NacosServerList的
服务获取和刷新的流程图什么时候获取服务其实当nacos客户端起来之后,并不会去请求服务信息,只是会去做服务注册,配置获取等,那什么时候会获取服务呢,就是第一次请求来的时候,也就是说是懒加载的思想,下面看我慢慢分析。拦截器拦截RestTemplate这个就不多说了,以前分析ribbon的时候有讲过,可以看这篇文章,我就大致的走个流程。首先是拦截:获取负载均衡器:创建服务对应的上下文,这里会传入服务名:向ribbon的属性源里添加一条值为服务名的属性,key为ribbon.client.name,名字为服务名:就是这样,属性源属性后面有用到。然后刷新上下文,RibbonClientConfigur
服务发现任务图NamingProxy的refreshSrvIfNeed刷新服务地址这个主要是刷新服务器地址用的,但是是根据域名去请求的,一般不设置域名这里基本都是返回了。privatevoidrefreshSrvIfNeed(){try{//有了服务了直接返回if(!CollectionUtils.isEmpty(serverList)){NAMING_LOGGER.debug("serverlistprovidedbyuser:"+serverList);return;}//间隔太短不行,30秒if(System.currentTimeMillis()-lastSrvRe
服务发现任务图SwitchRefresher故障转移刷新查看缓存目录下的/failover/00-00---000-VIPSRV_FAILOVER_SWITCH-000---00-00文件,看是否有改变,有改变就要设置相应的属性来表示是否开启故障转移模式,也就是做容灾备份的。@Overridepublicvoidrun(){try{//是否有转移文件FileswitchFile=newFile(failoverDir+UtilAndComs.FAILOVER_SWITCH);if(!switchFile.exists()){switchParams.put("failover-mod
服务发现任务图NacosWatch这个就不多说了,SmartLifecycle这个已经很熟悉了吧,调用start,里面开启任务,30秒一次,发送HeartbeatEvent,不过貌似现在没有监听器监听。BeatTask心跳任务服务注册默认是临时结点,所以要有心跳。其实就是发送心跳到/nacos/v1/ns/instance/beat,然后根据返回的信息设置属性,如果是没找到就注册服务。默认第一次是非轻量级的心跳,会发body的,body就是一堆服务信息的url编码的字符串,后面就不需要了,默认间隔5秒。@Overridepublicvoidrun(){if(beatInfo.isStopped
服务发现相关配置类介绍前面都讲了配置服务的原理,还有一个服务发现呢,主要是这些自动配置类。NacosDiscoveryAutoConfigurationNacosDiscoveryProperties服务发现属性和命名服务通过他可以直接获取命名服务,比如在负载均衡器ZoneAwareLoadBalancer初始化中获取服务的时候有用到,林另外他还是spring.cloud.nacos.discovery配置属性类:NacosServiceDiscovery通过NacosDiscoveryProperties的NamingService获取信息,将Instance封装成ServiceInstan
大致服务注册流程服务注册相关配置类介绍主要的也就一个NacosServiceRegistryAutoConfiguration。NacosServiceRegistryAutoConfigurationNacosServiceRegistry实现了ServiceRegistry接口,可以进行注册,注销等操作。拿到属性和命名服务,然后用命名服务可以进行注册的操作。NacosRegistration注册的服务实例,一些基本的信息服务都可以从这里获取。NacosAutoServiceRegistration继承了AbstractAutoServiceRegistration,就有一些服务注册的生命周
RefreshScope注解类实例化基本流程GenericScope的destroy这里就先把cache清空了,返回了BeanLifecycleWrapper集合。然后拿出前面创建的对应的写锁,上锁后,进行BeanLifecycleWrapper的销毁。@Overridepublicvoiddestroy(){List<Throwable>errors=newArrayList<Throwable>();Collection<BeanLifecycleWrapper>wrappers=this.cache.clear();for(BeanLifecycleW
RefreshScope注解类实例化基本流程ConfigurationPropertiesRebinder配置属性类重新绑定在刷新环境的最后会进行EnvironmentChangeEvent的通知:ConfigurationPropertiesRebinder就是处理这个事件的:ConfigurationPropertiesRebinder的rebind重新绑定重新绑定所有的配置属性对象的属性:rebind绑定那怎么绑定呢,其实很简单,因为绑定是在ConfigurationPropertiesBindingPostProcessor的postProcessBeforeInitializatio
RefreshScope注解类实例化基本流程nacos如何通过RefreshScope注解进行属性刷新RefreshScope注解原理说了几篇,接着这篇文章的刷新问题。回到NacosContextRefresher的registerNacosListener来,在接受到有配置修改的情况下,会进行监听器通知,然后这里面会进行RefreshEvent事件的通知:RefreshEventListener的handle主要是在RefreshEventListener这个监听器进行环境属性源的刷新,以及scope被代理对象缓存的释放。具体来看下这么做的。ContextRefresher的refresh其