文章目录
- 1.Nacos注册中心架构
- 2.核心功能
- 3.流程解析
1.Nacos注册中心架构
2.核心功能
服务注册:Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自身的元数据,比如ip地址、端口等信息。Nacos Server接收到注册请求后,就会把这些元数据信息存储在一个双层的内存Map中。
服务心跳:在服务注册后,Nacos Client会维护一个定时心跳来持续通知Nacos Server,说明服务一直处于可用状态,防止被剔除。默认5s发送一次心跳。
服务同步:Nacos Server集群之间会互相同步服务实例,用来保证服务信息的一致性。
服务发现:服务消费者(Nacos Client)在调用服务提供者的服务时,会发送一个REST请求给Nacos Server,获取上面注册的服务清单,并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务定时拉取服务端最新的注册表信息更新到本地缓存
服务健康检查:Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况,对于超过15s没有收到客户端心跳的实例会将它的healthy属性置为false(客户端服务发现时不会发现),如果某个实例超过30秒没有收到心跳,直接剔除该实例(被剔除的实例如果恢复发送心跳则会重新注册)
3.流程解析
1、客户端启动时会将当前服务的信息包含ip、端口号、服务名、分组名、集群名等信息封装为一个Instance对象,准备向Nacos服务器注册服务,在注册服务之前,会根据Instance中的信息创建一个BeatInfo对象,然后创建一个定时任务,每隔一段时间向Nacos服务器发送PUT请求并携带相关信息,作为定时心跳连接,服务器端在接收到心跳请求后,会去检查当前服务列表中有没有该实例,如果没有的话将当前服务实例重新注册,注册完成后立即开启一个异步任务,更新客户端实例的最后心跳时间,如果当前实例是非健康状态则将其改为健康状态;
2、心跳定时任务创建完成后,通过POST请求将当前服务实例信息注册进Nacos服务器,服务器端在接收到注册实例请求后,会将请求携带的数据封装为一个Instance对象,然后为这个服务实例创建一个服务Service,一个Service下可能有多个服务实例,服务在Nacos保存到一个ConcurrentHashMap中,格式为命名空间为key,value为map,分组名和服务名为内层map的key,value为服务数据,Map(namespace,Map(group::serviceName, Service));
3、服务创建完成之后,开启一个定时任务(5s),检查当前服务中的各个实例是否在线,如果实例上次心跳时间大于15s就将其状态设置为不健康,如果超出30s,则直接将该实例删除;
4、然后将当前实例添加到对应服务列表中,这里会通过synchronized锁住当前服务,然后分两种情况向集群中添加实例,如果是持久化数据,则使用基于CP模式的简单Raft协议,通过leader节点将实例数据更新到内存和磁盘文件中,并且通过CountDownLatch实现了一个简单的raft写入数据的逻辑,必须集群半数以上节点写入成功才会给客户端返回成功;
5、如果是非持久话实例数据,使用的是基于AP模式的Distro协议,首先向任务阻塞队列添加一个本地服务实例改变任务,去更新本地服务列表,然后在遍历集群中所有节点,分别创建数据同步任务放进阻塞队列异步进行集群数据同步,不保证集群节点数据同步完成即可返回;
6、在将服务实例更新到服务注册表中时,为了防止并发读写冲突,采用的是写时复制(CopyOnWrite)的思想,将原注册表数据拷贝一份,添加完成之后再替换回真正的注册表,更新完成之后,通过发布服务变化事件,将服务变动通知给客户端,采用的是UDP通信,客户端接收到UDP消息后会返回一个ACK信号,如果一定时间内服务端没有收到ACK信号,还会尝试重发,当超出重发时间后就不在重发,虽然通过UDP通信不能保证消息的可靠抵达,但是由于Nacos客户端会开启定时任务,每隔一段时间更新客户端缓存的服务列表,通过定时轮询更新服务列表做兜底,所以不用担心数据不会更新的情况,这样既保证了实时性,又保证了数据更新的可靠性;
7、服务发现:客户端通过定时任务定时从服务端拉取服务数据保存在本地缓存,服务端在发生心跳检测、服务列表变更或者健康状态改变时会触发推送事件,在推送事件中会基于UDP通信将服务列表推送到客户端,同时开启定时任务,每隔10s定时推送数据到客户端。