【Alibaba中间件技术系列】「Nacos技术专题」配置中心加载原理和配置实时更新原理分析(中)

本文涉及的产品
云原生网关 MSE Higress,422元/月
MSE任务调度普通实例型免费试用套餐,400 元额度,开发版规格
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: 【Alibaba中间件技术系列】「Nacos技术专题」配置中心加载原理和配置实时更新原理分析(中)

官方资源

nacos.io/zh-cn/docs/…




带着问题去思考


  • 客户端长轮询的响应时间会受什么影响
  • 为什么更改了配置信息后客户端会立即得到响应
  • 客户端的超时时间为什么要设置为30s
  • 带着以上这些问题我们从服务端的代码中去探寻结论。



Nacos之配置中心


  • 动态配置管理是 Nacos的三大功能之一,通过动态配置服务,可以在所有环境中以集中和动态的方式管理所有应用程序或服务的配置信息。
  • 动态配置中心可以实现配置更新时无需重新部署应用程序和服务即可使相应的配置信息生效,这极大了增加了系统的运维能力。



动态配置


Nacos的动态配置的能力,看看 Nacos是如何以简单、优雅、高效的方式管理配置,实现配置的动态变更的,接下来来了解下 Nacos 的动态配置的功能。




客户端动态化配置机制


Nacos 的客户端维护了一个长轮询的任务,去检查服务端的配置信息是否发生变更,如果发生了变更,那么客户端会拿到变更的 groupKey 再根据 groupKey 去获取配置项的最新值即可。


客户端去发请求,询问服务端我所关注的配置项有没有发生变更,如果间隔时间设置的太长的话有可能无法及时获取服务端的变更,如果间隔时间设置的太短的话,那么频繁的请求对于服务端来说无疑也是一种负担。


如果客户端每隔一段长度适中的时间去服务端请求,而在这期间如果配置发生变更,服务端能够主动将变更后的结果推送给客户端,这样既能保证客户端能够实时感知到配置的变化,也降低了服务端的压力。




客户端长轮询


客户端长轮询的部分,也就是LongPollingRunnable中的checkUpdateDataIds 方法,该方法就是用来访问服务端的配置是否发生变更的,该方法最终会调用如下图所示的方法:

image.png


http请求操作


客户端是通过一个http的post 请求去获取服务端的结果的,并且设置了一个超时时间:30s。一般来讲:客户端足足等了29.5+s,才请求到服务端的结果,然后客户端得到服务端的结果之后,再做一些后续的操作,全部都执行完毕之后,在 finally 中又重新调用了自身,也就是说这个过程是一直循环下去的。


长轮询执行逻辑


客户端向服务端发起一次请求,最少要29.5s才能得到结果,当然啦,这是在配置没有发生变化的情况下。如果客户端在长轮询时配置发生变更的话,该请求需要多长时间才会返回呢,在客户端长轮询时修改配置。


未获得到修改数据的操作触发返回

image.png

获得到了修改数据操作立刻触发返回

image.png

服务端controller


上面说到了客户端发送的 http 请求中可以知道,请求的是服务端的 /v1/cs/configs/listener 这个接口,com.alibaba.nacos.config.server.controller.ConfigController.java,在 ConfigController 类中,如下图所示:image.png

服务端是通过springMVC对外提供的 http 服务,对 HttpServletRequest 中的参数进行转换后,然后交给一个叫 inner 的对象去执行。inner 对象是 ConfigServletInner 类的实例,com.alibaba.nacos.config.server.controller.ConfigServletInner.javaimage.png

该方法是一个轮询的接口,除了支持长轮询外还支持短轮询的逻辑。再次进入 longPollingService 的 addLongPollingClient 方法,如下图所示:


com.alibaba.nacos.config.server.service.LongPollingService.javaimage.png

该方法主要是将客户端的长轮询请求添加到某个东西中去:服务端将客户端的长轮询请求封装成一个叫 ClientLongPolling 的任务,交给 scheduler 去执行。


服务端拿到客户端提交的超时时间后,又减去了 500ms 也就是说服务端在这里使用了一个比客户端提交的时间少 500ms 的超时时间,也就是 29.5s,看到这个 29.5s 我们应该有点兴奋了。


PS:这里的 timeout 不一定一直是 29.5,当 isFixedPolling() 方法为 true 时,timeout 将会是一个固定的间隔时间,这里为了描述简单就直接用 29.5 来进行说明。


接下来我们来看服务端封装的 ClientLongPolling 的任务到底执行的什么操作,如下图所示:


com.alibaba.nacos.config.server.service.LongPollingService.ClientLongPolling.java

image.png

ClientLongPolling 被提交给 scheduler 执行之后,实际执行的内容可以拆分成以下四个步骤:


  1. 创建一个调度的任务,调度的延时时间为 29.5s。
  2. 将该 ClientLongPolling 自身的实例添加到一个 allSubs 中去。
  3. 延时时间到了之后,首先将该 ClientLongPolling 自身的实例从 allSubs 中移除。
  4. 获取服务端中保存的对应客户端请求的 groupKeys 是否发生变更,将结果写入 response 返回给客户端。

image.png

allSubs 对象,该对象是一个 ConcurrentLinkedQueue 队列,ClientLongPolling 将自身添加到队列中。



调度任务


服务端对客户端提交上来的 groupKey 进行检查,如果发现某一个 groupKey 的 md5 值还不是最新的,则说明客户端的配置项还没发生变更,所以将该 groupKey 放到一个 changedGroupKeys 列表中,最后将该 changedGroupKeys 返回给客户端。对于客户端来说,只要拿到 changedGroupKeys 即可。



服务端数据变更


服务端直到调度任务的延时时间到了之前,ClientLongPolling 都不会有其他的任务可做,所以在这段时间内,该 allSubs 队列肯定有事情需要进行处理。


在客户端长轮询期间,更改了配置之后,客户端能够立即得到响应。



服务端数据变更接口


调用的请求,可以很容易的找到该请求对应的 url为:/v1/cs/configs 并且是一个 POST 请求,具体的方法是 ConfigController 中的 publishConfig 方法,如下图所示:

image.png

修改配置后,服务端首先将配置的值进行了持久化层的更新,然后触发了一个 ConfigDataChangeEvent 的事件,fireEvent 的方法:

com.alibaba.nacos.config.server.utils.event.EventDispatcher.java

image.png

fireEvent 方法实际上是触发的 AbstractEventListener 的 onEvent 方法,而所有的 listener 是保存在一个叫 listeners 对象中的。

image.png

被触发的 AbstractEventListener 对象则是通过 addEventListener 方法添加到 listeners 中的,找到 addEventListener 方法在何处被调用的,就知道有哪些 AbstractEventListener 需要被触发 onEvent 回调方法了。


可以找到是在 AbstractEventListener 类的构造方法中,将自身注册进去了,如下图所示:

com.alibaba.nacos.config.server.utils.event.EventDispatcher.AbstractEventListener.java

image.png

可以看到 AbstractEventListener 所有的子类中LongPollingService。当我们从 dashboard 中更新了配置项之后,实际会调用到 LongPollingService 的 onEvent 方法。


回到 LongPollingService 中,查看一下 onEvent 方法,如下图所示:

image.png

com.alibaba.nacos.config.server.service.LongPollingService.DataChangeTask.java

发现当触发了 LongPollingService 的 onEvent 方法时,实际是执行了一个叫 DataChangeTask 的任务,应该是通过该任务来通知客户端服务端的数据已经发生了变更,我们进入 DataChangeTask 中看下具体的代码,如下图所示:

image.png

遍历 allSubs 的队列


遍历 allSubs 的队列,该队列中维持的是所有客户端的请求任务,需要找到与当前发生变更的配置项的 groupKey 相等的 ClientLongPolling 任务



往客户端写响应数据


丢i与ClientLongPolling 任务后,只需要将发生变更的 groupKey 通过该 ClientLongPolling 写入到响应对象中,就完成了一次数据变更的 “推送” 操作了

如果 DataChangeTask 任务完成了数据的 “推送” 之后,需要将原来等待执行的调度任务取消掉了,这样就防止了推送操作写完响应数据之后,调度任务又去写响应数据。


可以从 sendResponse 方法中看到,确实是这样做的:

image.png

http请求本来就是无状态的,所以没必要也不能将超时时间设置的太长,这样是对资源的一种浪费。

image.png

与此同时服务端也将该请求封装成一个调度任务去执行,等待调度的期间就是等待 DataChangeTask 主动触发的,如果延迟时间到了 DataChangeTask 还未触发的话,则调度任务开始执行数据变更的检查,然后将检查的结果写入响应对象,如下图所示:

image.png



总结结论:


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


  1. Nacos 客户端能够实时感知到服务端配置发生了变化。


  1. 实时感知是建立在客户端拉和服务端“推”的基础上,但是这里的服务端“推”需要打上引号,因为服务端和客户端直接本质上还是通过 http 进行数据通讯的,之所以有“推”的感觉,是因为服务端主动将变更后的数据通过 http 的 response 对象提前写入了。



相关文章
|
4月前
|
消息中间件 存储 RocketMQ
消息中间件-RocketMQ技术(二)
消息中间件-RocketMQ技术(二)
|
4月前
|
消息中间件 存储 中间件
消息中间件-RocketMQ技术(一)
消息中间件-RocketMQ技术(一)
|
3月前
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
|
4月前
|
中间件 API 开发者
深入理解Python Web框架:中间件的工作原理与应用策略
在Python Web开发中,中间件位于请求处理的关键位置,提供强大的扩展能力。本文通过问答形式,探讨中间件的工作原理、应用场景及实践策略,并以Flask和Django为例展示具体实现。中间件可以在请求到达视图前或响应返回后执行代码,实现日志记录、权限验证等功能。Flask通过装饰器模拟中间件行为,而Django则提供官方中间件系统,允许在不同阶段扩展功能。合理制定中间件策略能显著提升应用的灵活性和可扩展性。
69 4
|
6月前
|
消息中间件 缓存 IDE
MetaQ/RocketMQ 原理问题之消息队列中间件的问题如何解决
MetaQ/RocketMQ 原理问题之消息队列中间件的问题如何解决
|
5月前
|
Kubernetes Nacos 微服务
【技术难题破解】Nacos v2.2.3 + K8s 微服务注册:强制删除 Pod 却不消失?!7步排查法+实战代码,手把手教你解决Nacos Pod僵死问题,让服务瞬间满血复活!
【8月更文挑战第15天】Nacos作为微服务注册与配置中心受到欢迎,但有时会遇到“v2.2.3 k8s 微服务注册nacos强制删除 pod不消失”的问题。本文介绍此现象及其解决方法,帮助开发者确保服务稳定运行。首先需检查Pod状态与事件、配置文件及Nacos配置,确认无误后可调整Pod生命周期管理,并检查Kubernetes版本兼容性。若问题持续,考虑使用Finalizers、审查Nacos日志或借助Kubernetes诊断工具。必要时,可尝试手动强制删除Pod。通过系统排查,通常能有效解决此问题。
123 0
|
5月前
|
Dubbo Java Nacos
【实战攻略】破解Dubbo+Nacos+Spring Boot 3 Native打包后运行异常的终极秘籍——从零开始彻底攻克那些让你头疼不已的技术难题!
【8月更文挑战第15天】Nacos作为微服务注册与配置中心受到欢迎,但使用Dubbo+Nacos+Spring Boot 3进行GraalVM native打包后常遇运行异常。本文剖析此问题及其解决策略:确认GraalVM版本兼容性;配置反射列表以支持必要类和方法;采用静态代理替代动态代理;检查并调整配置文件;禁用不支持的功能;利用日志和GraalVM诊断工具定位问题;根据诊断结果调整GraalVM配置。通过系统排查方法,能有效解决此类问题,确保服务稳定运行。
137 0
|
5月前
|
安全 Nacos 数据安全/隐私保护
【技术干货】破解Nacos安全隐患:连接用户名与密码明文传输!掌握HTTPS、JWT与OAuth2.0加密秘籍,打造坚不可摧的微服务注册与配置中心!从原理到实践,全方位解析如何构建安全防护体系,让您从此告别数据泄露风险!
【8月更文挑战第15天】Nacos是一款广受好评的微服务注册与配置中心,但其连接用户名和密码的明文传输成为安全隐患。本文探讨加密策略提升安全性。首先介绍明文传输风险,随后对比三种加密方案:HTTPS简化数据保护;JWT令牌减少凭证传输,适配分布式环境;OAuth2.0增强安全,支持多授权模式。每种方案各有千秋,开发者需根据具体需求选择最佳实践,确保服务安全稳定运行。
512 0
|
7月前
|
缓存 监控 Java
深入解析Nacos配置中心的动态配置更新技术
深入解析Nacos配置中心的动态配置更新技术
|
6月前
|
中间件 API 开发者
深入理解Python Web框架:中间件的工作原理与应用策略
【7月更文挑战第19天】Python Web中间件摘要:**中间件是扩展框架功能的关键组件,它拦截并处理请求与响应。在Flask中,通过`before_request`和`after_request`装饰器模拟中间件行为;Django则有官方中间件系统,需实现如`process_request`和`process_response`等方法。中间件用于日志、验证等场景,但应考虑性能、执行顺序、错误处理和代码可维护性。
96 0