Nacos,Ribbon,Feign 相关问题收集
Nacos,Ribbon,Feign 相关问题收集
Nacos原理图
Nacos注册中心
Nacos的服务注册表结构是怎样的?
Nacos采用了数据的分级存储模型,最外层是Namespace,用来隔离环境。然后是Group,用来对服务分组。接下来就是服务(Service)了,一个服务包含多个实例,但是可能处于不同机房,因此Service下有多个集群(Cluster),Cluster下是不同的实例(Instance)。
对应到Java代码中,Nacos采用了一个多层的Map来表示。结构为Map<String, Map<String, Service>>,其中最外层Map的key就是namespaceId,值是一个Map。内层Map的key是group拼接serviceName,值是Service对象。Service对象内部又是一个Map,key是集群名称,值是Cluster对象。而Cluster对象内部维护了Instance的集合。
Nacos注册中心原理
以Java版本的Nacos客户端为例,服务注册基本流程:
- 服务实例启动将自身注册到
Nacos
注册中心,随后维持与注册中心的心跳; - 心跳维持策略为每5秒向
Nacos Server
发送一次心跳,并携带实例信息(服务名、实例IP、端口等); Nacos Server
也会向Client主动发起健康检查,支持TCP/Http
;Nacos Server
端,15秒内无心跳且健康检查失败则认为实例不健康,如果30秒内健康检查失败则剔除实例;- 服务消费者通过注册中心获取实例,并发起调用;
其中服务发现支持两种场景:
-
服务消费者直接向注册中心发送获取某服务实例的请求,注册中心返回所有可用实例,但一般不推荐此种方式;
-
服务消费者向注册中心订阅某服务,并提交一个监听器,当注册中心中服务发生变化时,监听器会收到通知,消费者更新本地服务实例列表,以保证所有的服务均可用。
Nacos注册表如何防止多节点读写并发冲突
写时复制(读写分离)
不采用加锁的设计,可以保证高并发。当要更新实例时,先将内存中的注册表实例复制出来,跟要更新的实例对比,如果不一致,则去更新注册表中的实例。
Nacos如何支撑阿里内部数十万服务注册压力?
Nacos内部接收到注册的请求时,不会立即写数据,而是将服务注册的任务放入一个阻塞队列就立即响应给客户端。然后利用线程池读取阻塞队列中的任务,异步来完成实例更新,从而提高并发写能力。
服务消费者调用提供者
如果消费者订阅了服务,那么会在本地基于内存维护一个服务信息列表,之后进行服务调用是直接从本地列表获取对应的服务实例进行调用,否则去主从中心获取服务实例。
服务提供者与服务消费者之间是通过feign+ribbon进行配合调用的,feign提供http请求的封装以及调用,ribbon提供负载均衡。负载均衡有很多种实现方式,包括轮询法,随机方法法,对请求ip做hash后取模等等。 Nacos的客户端在获取到服务的完整实例列表后,会在客户端进行负载均衡算法来获取一个可用的实例,默认使用的是随机获取的方式.
Nacos配置中心
Nacos配置中心交互模型是push还是pull
客户端通过长轮询的方式拉取的.
客户端、控制台通过发送Http请求将配置数据注册到服务端,服务端持久化数据到Mysql。
客户端拉取配置数据,并批量设置对dataId的监听发起长轮询请求,如服务端配置项变更立即响应请求,如无数据变更则将请求挂起一段时间,直到达到超时时间。为减少对服务端压力以及保证配置中心可用性,拉取到配置数据客户端会保存一份快照在本地文件中,优先读取。
阿里面试这样问:Nacos配置中心交互模型是push还是pull ?(一)
服务消费者怎么获取Nacos配置信息
如果服务端配置与客户端一直没有变化
如果客户端拉取发现客户端与服务端配置是一致的(其实是通过MD5判断的)那么服务端会先拿住这个请求不返回,直到这段时间内配置有变化了才把刚才拿住的请求返回。他的步骤是nacos服务端收到请求后检查配置是否发生变化,如果没有则开启定时任务,延迟29.5s执行。同时把当前客户端的连接请求放入队列。那么此时服务端并没有将结果返回给客户端,当有以下2种情况的时候才触发返回。
- 就是等待29.5s后触发自动检查
- 在29.5s内有配置进行了更改
经过这2种情况才完成这次的pull操作。这种的好处就是保证了客户端的配置能及时变化更新,也减少了轮询给服务端带来的压力。
比客户端 30s
的超时时间提前 500ms
返回是为了最大程度上保证客户端不会因为网络延时造成超时。
Nacos服务如何多节点同步配置信息
服务端一般是多节点部署的集群,因此请求一开始只会打到一台机器,这台机器将配置插入 MySQL
中进行持久化.
因为服务端并不是针对每次配置查询都去访问 MySQL
的,而是会依赖 dump
功能在本地文件中将配置缓存起来。因此当单台机器保存完毕配置之后,需要通知其他机器刷新内存和本地磁盘中的文件内容,因此它会发布一个名为 ConfigDataChangeEvent
的事件,这个事件会通过 HTTP
调用通知所有集群节点(包括自身),触发本地文件和内存的刷新。
Nacos服务如何处理消费者获取配置信息的长轮询请求
客户端会有一个长轮询任务,拉取服务端的配置变更,那么服务端是如何处理这个长轮询任务的呢?源码逻辑位于 LongPollingService
类,其中有一个 Runnable
任务名为 ClientLongPolling
,服务端会将受到的轮询请求包装成一个 ClientLongPolling
任务,该任务持有一个 AsyncContext
响应对象(Servlet 3.0
的新机制),通过定时线程池延后 29.5s
执行。
为什么比客户端
30s
的超时时间提前500ms
返回是为了最大程度上保证客户端不会因为网络延时造成超时
这里需要注意的是,在 ClientLongPolling
任务被提交进入线程池待执行的同时,服务端也通过一个队列 allSubs
保存了所有正在被夯住的轮询请求,这是因为在配置项被夯住的期间内,如果用户通过管理平台操作了配置项变更、或者服务端该节点收到了来自其他节点的 dump
刷新通知,那么都应立即取消夯住的任务,及时通知客户端数据发生了变更。
Eureka、ZooKeeper、Nacos 区别
Eureka 不能支撑大量服务实例,因为 Eureka 的每个节点数据都一致,会产生大量的心跳检查等等导致并发性能低下,ZooKeeper 的频繁上下线通知会导致性能下降,而 Nacos 可以支持大量服务实例又不丢性能,据说服务数量能达到 10 万以上。
Eureka、ZooKeeper、Nacos、Consul 对比
- Eureka 适用于服务实例数量不大的服务注册中心;
- ZooKeeper 相对服务注册中心来说更适用于分布式协调服务;
- Nacos 既适用于大量服务实例的服务注册中心,也可以作为配置中心;
- Consul 更适用于 Service Mesh 架构,使用 Go 语言开发,不方便排查 Bug。
Ribbon-常见的负载均衡算法
- 随机,通过随机选择服务进行执行,一般这种方式使用较少;
- 轮训,负载均衡默认实现方式,请求来之后排队处理;
- 加权轮训,通过对服务器性能的分型,给高配置,低负载的服务器分配更高的权重,均衡各个服务器的压力;
- 地址Hash,通过客户端请求的地址的HASH值取模映射进行服务器调度;
- 最小链接数,即使请求均衡了,压力不一定会均衡,最小连接数法就是根据服务器的情况,比如请求积压数等参数,将请求分配到当前压力最小的服务器上;
Ribbon原理图
Ribbon-饥饿加载
在进行服务调用的时候,如果网络情况不好,第一次调用会超时。Ribbon默认懒加载,初始化负载均衡器,意味着只有在发起调用的时候才会创建客户端。
开启饥饿加载,解决第一次调用慢的问题
# 开启ribbon饥饿加载
ribbon.eager-load.enabled=true
# 指定需要饥饿加载的客户端名称、服务名,多个使用逗号分隔
ribbon.eager-load.clients=server-order
nacos中的ribbon,以及2021版
nacos-discovery依赖了ribbon,可以不用再引入ribbon依赖。
在服务中添加配置,添加 @LoadBalanced 注解。
五、Spring Cloud Alibaba项目,Ribbon
Feign使用的一些配置
http配置
#feign 关闭 httpclient
feign.httpclient.enabled=false
#feign 使用 okhttp
feign.okhttp.enabled=true
压缩配置
# 开启配置
feign.compression.request.enabled=true
feign.compression.response.enabled=true
# 配置压缩类型
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 最小压缩值
feign.compression.request.min-request-size=2048
注意:只有当 Feign 的 Http Client 不是 okhttp3 的时候,压缩才会生效,配置源码在FeignAcceptGzipEncodingAutoConfiguration
编解码配置:
# 对应的微服务"service-order"配置编解码器
feign.client.config.service-order.encoder=feign.jackson.JacksonEncoder
feign.client.config.service-order.decoder=feign.jackson.JacksonEncoder
六、Spring Cloud Alibaba项目,Feign