注册中心原理
官网:Nacos 注册中心的设计原理 | Nacos
nacos注册中心采用了 :pull (客户端的轮询)和push (服务端主动push)策略
- 客户端启动时会将当前服务的信息包含ip、端口号、服务名、集群名等信息封装为一个Instance对象,然后创建一个定时任务,每隔一段时间向Nacos服务器发送PUT请求并携带相关信息。
- nacos服务器端在接收到心跳请求后,会去检查当前服务列表中有没有该实例,如果没有的话将当前服务实例重新注册,注册完成后立即开启一个异步任务,更新客户端实例的最后心跳时间,如果当前实例是非健康状态则将其改为健康状态。
- nacos在更新完成之后,通过发布服务变化事件,将服务变动通知给客户端,采用的是UDP通信,客户端接收到UDP消息后会返回一个ACK信号,如果一定时间内服务端没有收到ACK信号,还会尝试重发,当超出重发时间后就不在重发。
- 客户端通过定时任务定时从服务端拉取服务数据保存在本地缓存。
- 服务端在发生心跳检测、服务列表变更或者健康状态改变时会触发推送事件,在推送事件中会基于UDP通信将服务列表推送到客户端,虽然通过UDP通信不能保证消息的可靠抵达,但是由于Nacos客户端会开启定时任务,每隔一段时间更新客户端缓存的服务列表,通过定时轮询更新服务列表做兜底,所以不用担心数据不会更新的情况,这样既保证了实时性,又保证了数据更新的可靠性。
数据一致性方案
nacos 目前的instance有一个ephemeral字段属性,该字段表示实例是否是临时实例还是持久化实例。
#false为永久实例,true表⽰临时实例开启,注册为临时实例,默认是true
spring.cloud.nacos.discovery.ephemeral=true
如果是临时实例则不会在nacos中持久化,则nacos使用的是AP模式,需要通过心跳上报,如果一段时间没有上报心跳,则会被nacos服务端删除。删除后如果又重新开始上报,则会重新实例注册。这种特性适合于需要应对流量突增的场景,服务可以弹性扩容,当流量过去后,服务停掉即可自动注销。
而持久化实例会被nacos服务端持久化,则nacos使用的是CP模式,此时即使注册实例的进程不存在,这个实例也不会删除,只会将健康状态设置成不健康。它的优点就是可以实时的监控到实例的健康状态,便于后续的告警和扩容等一系列处理。
- CP模式就是基于Raft协议(通过leader节点将实例数据更新到内存和磁盘文件中,并且通过CountDownLatch实现了一个简单的raft写入数据的逻辑,必须集群半数以上节点写入成功才会给客户端返回成功)
- AP模式基于Distro协议(向任务阻塞队列添加一个本地服务实例改变任务,去更新本地服务列表,然后在遍历集群中所有节点,分别创建数据同步任务放进阻塞队列异步进行集群数据同步,不保证集群节点数据同步完成即可返回)
- nacos在将服务实例更新到服务注册表中时,为了防止并发读写冲突,采用的是写时复制的思想,将原注册表数据拷贝一份,添加完成之后再替换回真正的注册表。
Nacos服务健康检查方案
Nacos 中提供了两种健康检查机制:
- 客户端主动上报机制。
- 服务器端反向探测机制。
临时实例采用客户端上报模式:客户端会定时通过RPC连接向注册中心发送心跳,告知nacos 注册中心健康状态(默认心跳间隔5s,nacos将超过超过15s未收到心跳的实例设置为不健康,超过30s将实例删除)
永久实例采用服务端主动检测:nacos主动检查客户端的健康状态(默认时间间隔20s,健康检查失败后会设置为不健康,不会立即删除)Nacos 现在内置提供了三种探测的协议,即 Http、TCP 以及 MySQL 。
配置中心原理
官网:配置一致性模型 | Nacos
Nacos1.x 采用 Http 1.1 短链接模拟长链接,每 30s 发一个心跳跟 Server 对比 SDK 配置 MD5 值是否跟 Server 保持一致,如果一致就 hold 住链接,如果有不一致配置,就把不一致的配置返回,然后 SDK 获取最新配置值。
- Nacos 客户端会循环请求服务端变更的数据,并且超时时间设置为30s,当配置发生变化时,请求的响应会立即返回,否则会一直等到 29.5s+ 之后再返回响应
- 客户端的请求到达服务端后,服务端将该请求加入到一个叫 allSubs 的队列中,等待配置发生变更时 DataChangeTask主动去触发,并将变更后的数据写入响应对象。
- 与此同时服务端也将该请求封装成一个调度任务去执行,等待调度的期间就是等DataChangeTask 主动触发的,如果延迟时间到了 DataChangeTask 还未触发的话,则调度任务开始执行数据变更的检查,然后将检查的结果写入响应对象(基于文件的MD5)
Nacos 2.x 相比上面 30s 一次的长轮训,升级成长链接模式,配置变更,启动建立长链接,配置变更服务端推送变更配置列表,然后 SDK 拉取配置更新,因此通信效率大幅提升。