面试系列之-Nacos原理

2023-11-20 15:00:08 浏览数 (2)

Nacos实现技术和原理

Nacos的实现技术和原理主要包含以下几个方面:

  1. Spring Cloud和Spring Boot:Nacos使用Spring Cloud作为服务治理的核心组件,使用Spring Boot作为开发框架。Spring Cloud提供了对Eureka、Consul等服务治理组件的支持;
  2. Raft算法:Nacos使用了Raft算法作为分布式一致性算法。Raft算法保证了分布式环境下数据的一致性,并且可以容忍节点故障;
  3. 数据库:Nacos使用MySQL作为存储服务注册和配置信息的数据库;
  4. RPC框架:Nacos使用了gRPC作为远程过程调用框架;
  5. Spring Cloud Gateway:Nacos使用Spring Cloud Gateway作为网关,处理所有的服务请求;
nacos高性能实现原理

nacos通过使用Raft算法来实现服务列表的同步和高并发访问。Raft算法是一种分布式一致性算法,能够保证在网络分区、服务器崩溃等异常情况下,系统仍能够保持强一致性。

nacos中的每个节点都是一个Raft节点,节点之间通过Raft协议进行通信和协调。当有节点加入或离开集群时,Raft算法会自动进行选举,选出一个新的leader来负责更新服务列表,并将最新的服务列表同步给其他节点。同时,nacos使用了一些优化技术来提高同步效率和并发访问性能,包括:

  1. 快照技术:nacos会定期生成快照,将当前的服务列表状态保存下来,当节点重新加入集群时,可以快速恢复服务列表的状态,避免了重新同步的过程。
  2. 数据压缩:nacos使用了一些数据压缩算法来压缩服务列表数据,减少网络传输的数据量,提高同步效率。
  3. 前缀树:nacos中的服务列表使用了前缀树数据结构进行存储和管理,能够快速地进行服务的查找和匹配,提高了并发访问性能。
nacos特性

服务注册:客户端在第一次注册时会调用一个http请求,将服务注册的信息注册到Nacos,服务端收到请求之后,会将实例信息封装成一个bean,然后放到BlockQueue阻塞队列中,在Nacos启动时会单起一个线程来消费队列中新注册过来的实例,在实例注册时采用copy on write的技术,保证不影响实例内存对象Map的读取;

服务心跳:当客户端注册实例之后,之后会开启一个定时任务,每5秒向服务端发送一个心跳,防止被剔除;

服务健康状态:Nacos在启动时会启动一个定时任务,每5秒跑一次,当15秒之内没有收到服务的心跳时,会将服务的健康状态设置为false,在30秒还没有收到心跳时,会直接剔除(针对临时实例);

服务发现:客户端调用其他服务时,会先调用一个http请求,从Nacos中获取全部实例同时存储到本地内存中,并且会开启一个定时任务,每5秒拉取一次服务,这时会存在有些实例在这5秒有问题,可以通过rabbon的重置机制来结合使用;

集群服务同步:Nacos集群会通过hash选取一个健康监测的服务,如果服务列表有变动,会推送给其他服务;

Nacos服务注册原理

服务注册时在服务端本地会通过轮询注册中心集群节点地址进行服务得注册,在注册中心上,即Nacos Server上采用了Map保存实例信息,当然配置了持久化的服务会被保存到数据库中,在服务的调用方,为了保证本地服务实例列表的动态感知,Nacos与其他注册中心不同的是,采用了 Pull/Push同时运作的方式。

服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务;服务注册的策略的是每5秒向nacos server发送一次心跳,心跳带上了服务名,服务ip,服务端口等信息,同时 nacos server也会向client 主动发起健康检查,支持tcp/http检查;如果15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例;

Nacos注册概括来说有6个步骤:

  1. 服务容器负责启动,加载,运行服务提供者;
  2. 服务提供者在启动时,向注册中心注册自己提供的服务;
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务;
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者;
  5. 服务消费者从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心;
服务注册

服务注册的主要过程就是,将服务列表更新的通知放入阻塞队列。 服务端启动时候会开启一个线程,专门从这个阻塞队列中获取通知,拿到最新的服务列表,并更新到service中的clusterMap中去。也就是更新最底层Cluster中的ephemeralInstances变量,此变量就是存放当前cluster下的所有服务列表;

服务发现

客户端发起服务获取的请求。服务端获取客户端服务所在的service下的所有cluster下的服务列表,并剔除其中不健康的,将所有健康状态的服务列表返回给客户端。

服务同步

nacos中临时实例集群同步采用的是AP模式,而持久实例采用的是CP模式,CP和AP模式可以自行指定;

服务同步本质上也就是将更新的服务序列化,调用同步服务的接口,传递给集群中其他节点。 不过这里有个小问题。就是如果其他节点出现问题,比如挂了。那么这里肯定同步不成功,那么它会不断的重试,不断的执行同步调用,又不断的失败。这样其实是无意义的,作者在这里也标注了,之后会更新,使用其他重试机制。比如,重试的时间延长,失败次数如果达到某个次数,就停止同步。

同步服务的接口和之前的服务注册、删除过程一样。同样的获取接口参数,拿出要同步的服务信息,将服务封装起来,添加一个服务变更通知到阻塞队列。让其他线程去阻塞队列取数据,然后完成服务列表的更新;

服务端推送

客户端向服务端拉取数据的同时,会将客户端信息注册到clientMap中。等到下一次发生心跳、服务列表数据变更、健康状态发生变化等,都会触发推送事件。在推送事件方法中,服务端将此客户端对应的service下的所有服务列表基于UDP推送给客户端,并开启一个定时任务,每隔10s定时推送数据到客户端。

服务健康检查

如果最后心跳时间与当前时间差超过15s就会设置为false,也就是掉线。时间差超过30s就会将此服务踢出服务列表。

服务心跳

客户端在启动的时候,会开启一个心跳线程,每隔5s调用一次服务端的心跳接口(Http调用),服务端将心跳请求封装成一个task,放到线程池中。由服务端的线程池执行task,更新对应服务的最后心跳时间;

Nacos Server 的注册表结构

Nacos的注册表结构设计方式是一个双重Map结构,定义如下:

源码中注释其实已经解释这个双重Map数据结构的存储结构,最外层的Map的Key为Namespace,Value为一个Map,内层的Map的Key为group::serviceName,Value为Service对象。Service对象中也有一个Map的数据结构,如下:

Map的Key值为Cluster的名字,Value为Cluster对象,Cluster对象中有两个Set的数据结构,用来存储Instance,这个Instance才是真正的客户端注册过来的实例信息。

这里有两个Set,一个是用来存储临时实例,一个是用来存储持久化实例,有个关键点,什么情况会存储在临时实例,什么情况下会存储持久化实例,这个是由客户端的配置来决定的,默认情况下客户端配置ephemeral=true,如果你想把实例用持久化的方式来存储,可以设置ephemeral=false,这样在客户端发起注册的时候会把这个参数带到Nacos Server,Nacos Server就会按照持久化的方式来存储。

注意:Nacos目前持久化存储的方式采用的是本地文件存储的方式。

Nacos配置中心原理
推拉模式
  • 客户端主动从服务端定时拉取配置,如果有变化则进行替换;
  • 服务端主动把变化的内容发送给客户端;

两种方式各有利弊,比如对于推的模式来讲,就需要服务端与客户端进行长连接,那么这种就会出现服务端需要耗费大量资源维护这个链接,并且还得加入心跳机制来维护连接有效性。而对于拉的模式则需要客户端定时去服务端访问,那么就会存在时间间隔,也就保证不了数据的实时性;nacos是采用了拉模式是一种特殊的拉模式,也就是通常听的长轮询机制;

如果客户端拉取发现客户端与服务端配置是一致的(其实是通过MD5判断的)那么服务端会先拿住这个请求不返回,直到这段时间内配置有变化了才把刚才拿住的请求返回。他的步骤是nacos服务端收到请求后检查配置是否发生变化,如果没有则开启定时任务,延迟29.5s执行。同时把当前客户端的连接请求放入队列。那么此时服务端并没有将结果返回给客户端,当有一下2种情况的时候才触发返回:

  • 就是等待29.5s后触发自动检查
  • 在29.5s内有配置进行了更改

经过这2种情况才完成这次的pull操作。这种的好处就是保证了客户端的配置能及时变化更新,也减少了轮询给服务端带来的压力。所以之前文章我们说过这个长链接回话超时时间默认是30s;

换句话总结来说:Nacos 客户端会循环请求服务端变更的数据,并且超时时间设置为30s,当配置发生变化时,请求的响应会立即返回,否则会一直等到 29.5s 之后再返回响应;

Spring Cloud Config 横向对比Nacos Config

  1. Spring Cloud Config需要结合Git使用,动态变更需要配合Bus 消息总线来通知所有的客户端变化;
  2. Spring Cloud Config没有可视化界面;
  3. Nacos使用长轮询更新配置,速度上秒杀Spring Cloud Config;

0 人点赞