nacos面试总结(其一)
什么是nacos
?nacos
有什么作用?
nacos
是一个开源的分布式服务发现和配置管理系统,它的主要作用是服务注册、发现和配置管理。
Nacos
的主要功能和作用包括:
- 服务发现与注册:
Nacos
可以用于服务的注册和发现,使微服务架构中的各个服务能够相互发现和调用,从而实现服务之间的协作和通信。服务提供者在启动时将自己注册到Nacos
服务器,服务消费者可以从Nacos
服务器获取服务提供者的地址。- 动态配置管理:
Nacos
提供了一个集中式的配置管理功能,允许开发人员动态管理应用程序的配置。配置可以存储在Nacos
服务器上,并且可以根据需要在运行时动态刷新,无需重启应用程序。这有助于实现敏捷的配置管理和快速的配置变更。- 服务健康监测:
Nacos
可以监测注册的服务的健康状态,如果服务不可用或出现问题,Nacos
可以通知其他服务或自动进行实例剔除,以确保系统的可用性。- 动态路由配置:
Nacos
支持动态配置路由规则,可以用于实现服务的动态路由,例如灰度发布、AB测试等。- 多数据中心支持:
Nacos
具备多数据中心的支持,这意味着你可以在不同的地理位置部署Nacos
服务器,并跨数据中心注册和发现服务。- 事件监听和通知:
Nacos
支持事件监听和通知机制,当服务的状态或配置发生变化时,可以通知相关的应用程序,从而实现自动化的反应和处理。
Nacos
架构
Nacos
1.X 架构层次
具体描述:
Nacos
1.X 大致分为 5 层, 分别是接入、通信、功能、同步和持久化。
接入层是用户最直接交互的层面,主要有 Nacos
客户端,以及依赖客户端的 Dubbo 和 SCA 以及用户操作的控制台 Console 组成。客户端和 Console 进行服务和配置操作,统一通过 HTTP 的 OpenAPI
发起通信请求。
通信层主要基于 HTTP 的短连接请求模型进行,部分推送功能通过 UDP 进行通信。
功能目前有服务发现和配置管理,这层也就是实际管理服务和配置的业务层。
同步层有数据同步的 AP 模式 Distro 和 CP 模式 Raft,还有有一个最简易的水平通知 Notify,用处各不相同:
- Distro:非持久化服务的同步模式。
- Raft:持久化服务的同步模式、以及使用 Derby 作为配置的存储时同步配置操作。
- Notify:使用 MySQL 作为配置的存储时,通知其他节点更新缓存及发起配置推送。
持久化层 Nacos
使用 MySQL、Derby 和本地文件系统来进行数据的持久化 配置信息,用户信息,权限信息存储在 MySQL 或 Derby 数据库中, 持久化服务信息及服务和实例元数据信息存储在本地文件系统。
存在问题:
- 心跳数量多,导致 TPS 居高不下
通过心跳续约,当服务规模上升时,特别是类似 Dubbo 的接口级服务较多时,心跳及配置元数据的轮询数量众多,导致集群 TPS 很高,系统资源高度空耗。
- 通过心跳续约感知服务变化,时延长
心跳续约需要达到超时时间才会移除并通知订阅者,默认为 15s,时延较长,时效性差。若改短超时时间,当网络抖动时,会频繁触发变更推送,对客户端服务端都有更大损耗。
- UDP 推送不可靠,导致 QPS 居高不下
由于 UDP 不可靠,因此客户端测需要每隔一段时间进行对账查询,保证客户端缓存的服务列表的状态正确,当订阅客户端规模上升时,集群 QPS 很高,但大多数服务列表其实不会频繁改变,造成无效查询,从而存在资源空耗。
- 基于 HTTP 短连接模型,TIME_WAIT 状态连接过多
HTTP 短连接模型,每次客户端请求都会创建和销毁 TCP 链接,TCP 协议销毁的链接状态是 WAIT_TIME,完全释放还需要一定时间,当 TPS 和 QPS 较高时,服务端和客户端可能有大量的 WAIT_TIME 状态链接,从而会导致 connect time out 错误或者 Cannot assign requested address 的问题。
- 配置模块的 30 秒长轮询引起的频繁 GC
配置模块使用 HTTP 短连接阻塞模型来模拟长连接通信,但是由于并非真实的长连接模型,因此每 30 秒需要进行一次请求和数据的上下文切换,每一次切换都有引起造成一次内存浪费,从而导致服务端频繁 GC。
Nacos
2.0 架构层次
具体描述:
通信层目前通过 gRPC
和 Rsocket
实现了长连接 RPC 调用和推送能力。
在服务端测,新增一个链接层,用来将不同类型的 Request 请求,将来自不同客户端的不同类型请求,转化为相同语意的功能数据结构,复用业务处理逻辑。同时,将来的流量控制和负载均衡等功能也会在链接层处理。
其他架构分层在大体上保持不变。
优点
- 客户端不再需要定时发送实例心跳,只需要有一个维持连接可用 keepalive 消息即可。重复 TPS 可以大幅降低。
- TCP 连接断开可以被快速感知到,提升反应速度。
- 长连接的流式推送,比 UDP 更加可靠;nio 的机制具有更高的吞吐量,而且由于可靠推送,可以加长客户端用于对账服务列表的时间,甚至删除相关的请求。重复的无效 QPS 可以大幅降低。
- 长连接避免频繁连接开销,可以大幅缓解 TIME_ WAIT 问题。
- 真实的长连接,解决配置模块 GC 问题。
- 更细粒度的同步内容,减少服务节点间的通信压力。
缺点
没有银弹的方案,新架构也会引入一些新问题:
- 内部结构复杂度上升,管理连接状态,连接的负载均衡需要管理。
- 数据又原来的无状态,变为与连接绑定的有状态数据,流程链路更长。
- RPC 协议的观测性不如 HTTP。即使 gRPC 基于 HTTP2.0Stream 实现,仍然不如直接使用 HTTP 协议来的直观。
什么是CAP理论,nacos
是CP还是AP?
CAP理论的三个属性解释如下:
- 一致性(Consistency):在分布式系统中,一致性表示在任何时刻,所有节点对于同一份数据的访问都会返回相同的数据值。这意味着无论客户端向系统的哪个节点发出请求,它们都应该得到相同的答案。一致性要求分布式系统在数据更新后立即反映出这些变更,这可能需要牺牲部分可用性。
- 可用性(Availability):可用性表示分布式系统在有限时间内能够对客户端的请求做出响应,即系统保持运行,不会因为节点的故障或其他问题而停止响应请求。可用性要求分布式系统在出现故障时仍然能够提供服务,即使是部分服务。
- 分区容忍性(Partition Tolerance):分区容忍性表示分布式系统在面临网络分区(节点之间的通信断开或延迟)的情况下仍然能够正常运行。分布式系统通常需要跨越多个网络节点,因此网络分区可能是不可避免的,分区容忍性要求系统在分区发生时能够继续工作。
nacos
支持AP(可用性 | 分区容错性) 和 CP(一致性 | 分区容错性)两种 默认是AP如果注册
Nacos
的client节点注册时 ephemeral=true(临时节点/永久节点),那么Nacos
集群对这个client节点的效果就是AP,采用distro协议实现;而注册Nacos
的client节点注册时ephemeral=false,那么Nacos
集群对这个节点的效果就是CP的,采用raft协议实现。根据client注册时的属性,AP,CP同时混合存在,只是对不同的client节点效果不同。Nacos
可以很好的解决不同场景的业务需求。
Nacos
为什么要区分临时节点和永久节点?
Nacos
之所以区分临时节点和永久节点,是因为这两种节点具有不同的生命周期和用途,以满足不同场景下的需求。这种区分是为了提供更灵活的服务注册与发现以及配置管理功能。以下是临时节点和永久节点的主要区别和用途:
临时节点(Ephemeral Nodes):
生命周期短暂:临时节点的生命周期与服务实例的生命周期相对应。当一个服务实例注册一个临时节点时,它会在Nacos服务器上保持活动状态,只要该服务实例保持运行,节点就存在。一旦服务实例终止或主动注销,节点将被自动删除。
适用于动态服务:临时节点通常用于表示动态的、可能经常启动和关闭的服务实例。这对于微服务架构中的服务注册与发现非常有用,因为它们能够自动反映服务实例的状态。
永久节点(Persistent Nodes):
持久存在:永久节点在注册后将一直存在,直到显式删除。它们不会因为服务实例的终止而被自动删除,只会将健康状态标记为不健康,只有在进行手动删除操作时才会被移除。
适用于静态配置:永久节点通常用于存储静态配置信息或全局的服务信息,这些信息不会频繁改变。例如,全局配置、共享资源、重要的服务信息等可以存储在永久节点中,以供各个服务实例访问。
通过区分临时节点和永久节点,Nacos可以适应不同的应用场景。临时节点使得服务实例能够动态注册和注销,从而实现高度动态的服务发现。永久节点则用于存储静态的配置和全局信息,以供所有服务实例访问,确保这些信息在整个系统中保持一致。
这种区分还有助于提高系统的可伸缩性和性能,因为Nacos
可以更有效地管理临时节点,而不必关心永久节点的生命周期。这有助于优化服务注册与发现的性能和资源利用率。
Nacos
中的保护阈值的作用是什么?
假如现在有一个服务,本来有10个实例,但是现在挂掉了8个,剩下2个正常实例,此时本来由10个实例处理的流量,就全部交给这个两个正常实例来处理了,此时这两个实例很有可能是处理不过来的,最终导致被压垮,为了应对这种情况,Nacos
提供了保护阈值这个功能,我们可以给某个服务设置一个0-1的阈值,比如0.5,那就表示,一旦实例中只剩下一半的健康实例了,比如10个实例,只剩下5个健康实例了,那么消费者在进行服务发现时,则会把该服务的所有实例,也包括不健康的实例都拉取到本地,然后再从所有实例中进行负载均衡,选出一个实例进行调用,在这种情况下,选出来的即可能是一个健康的实例,也可能是挂掉的实例,但是通过这种方式,很好的保护的剩下的健康实例,至少保证了一部分请求能正常的访问,而不至于所有请求都不能正常访问,这就是Nacos
中的保护阈值,同时,这个功能在Spring Cloud Tencent中叫全死全活。
Nacos
中的负载均衡是怎么样的?
Nacos
的负载均衡指的是,在进行服务发现时进行负载均衡,正常情况下,在进行服务发现时,会根据服务名从Nacos
中拉取所有的实例信息,但是Nacos
中提供了一个功能,就是可以在拉取实例时,可以根据随机策略只拉取到所有实例中的某一个,这就是Nacos
中的负载均衡,它跟Ribbon
的负载均衡并不冲突,可以理解为Ribbon
的负载均衡是发生在Nacos
的负载均衡之后的。
Nacos
的就近访问是什么意思?
首先,在Nacos
中,一个服务可以有多个实例,并且可以给实例设置cluster-name,就是可以再进一步的给所有实例划分集群,那如果现在某个服务A想要调用服务B,那么Naocs
会看调用服务A的实例是属于哪个集群的,并且调用服务B时,那就会调用同样集群下的服务B实例,根据cluster-name
来判断两个实例是不是同一个集群,这就是Nacos
的就近访问。
Nacos
如何避免并发读写冲突问题?
Nacos
在更新实例列表时,会采用CopyOnWrite
(写时复制)技术,首先将旧的实例列表拷贝一份,然后更新拷贝的实例列表,再用更新后的实例列表来覆盖旧的实例列表。
这样在更新的过程中,就不会对读实例列表的请求产生影响,也不会出现脏读问题了。