配置中心的坑:热更新不等于立即生效

举报
yd_293849122 发表于 2026/10/29 22:18:40 2026/10/29
【摘要】 一次修改 Nacos 配置后,控制台显示发布成功,实例却仍用旧值。本文记录我从长轮询、@RefreshScope、静态缓存到 Actuator 验证的排查过程,给出 refresh-enabled、timeout 等配置和 curl 巡检命令,并总结三条避免“热更新不立即生效”的经验。

上周五下午,在华为云微服务引擎CSE的Nacos配置中心里把订单服务的`feature.ratio`由原来的0.2改为现在的0.5,并且提示发布成功。根据我的经验,在热更新之后几秒钟之内所有的实例都应该切换到新的比例上。但是灰度实例的日志还是显示的是`ratio=0.2`,直到我手动重启之后才生效。那时候我才明白过来:配置中心的热更新其实只是“变更通知”、“重新绑定”,并没有真正改变业务逻辑所使用的值。

首先检查链路情况,Nacos控制台显示对于数据Id为`order-service.yaml`、组名为`DEFAULT_GROUP`的数据的MD5已经更新了;使用`curl http://nacos:8848/nacos/v1/cs/configs?dataId=order-service.yaml&group=DEFAULT_GROUP`也可以获取到最新的配置信息。由此可以推测配置中心方面没有问题,问题出在客户端上。客户端与Nacos之间的长轮询默认为每30秒发送一次请求,服务端会hold住请求,在有变更的时候才会给出响应;但是在中间有SLB或者网关把空闲连接掐断为60秒左右的时间间隔的情况下,客户端会重新尝试连接,但是通知可能会有延迟。我抓包发现实例在30秒之内收到了变更的消息,但是业务值并没有改变。

继续看代码,发现有3处问题。第一,读取配置的类只写了 `@Value("${feature.ratio:0.2}")`,但是没有 `@RefreshScope`。Spring容器中的该Bean是单例,`@Value`只在创建时注入1次,RefreshEvent不会重建它。第二,我在类中用`static final Map`缓存了开关,配置监听器收到了新的值,但是缓存没有被清空。第三,`@ConfigurationProperties`所在的Bean被手动new出来,并没有交给Spring管理,所以自然不在刷新范围内。

按照我的原则,在配置发生变化的时候要经过“通知、刷新、清理、验证”的四个步骤:把配置项收敛到OrderProperties,并且添加上@ConfigurationProperties(prefix="feature")、@RefreshScope;把所有的静态缓存都移除掉,只保留一个@EventListener(RefreshEvent.class)来清除本地缓存;在application.yml文件中显式地开启刷新功能:spring.cloud.nacos.config.refresh-enabled=true,并且设置好spring.cloud.nacos.config.timeout为3000毫秒;默认情况下refresh-enabled是开启的,但是把它显式的写出来可以防止被环境变量所覆盖;timeout为3000毫秒,用来防止在网络抖动的情况下长时间轮询线程被拖死。之后再调用curl -X POST http://localhost:8080/actuator/refresh来获取刷新范围命中信息,并且把新的值显示出来;最后再查看curl http://localhost:8080/actuator/env/feature.ratio返回的结果,看看是否有新的值出现。如果没有开启actuator,则要在management.endpoints.web.exposure.include中添加refresh和env这两个前缀。

发布流程也做了相应的调整:首先发布配置信息,之后等待30秒左右的时间,在此期间使用`curl`来检查每一个实例上 `/actuator/env` 和业务健康检查的结果,并且不只查看Nacos控制台中的“发布成功”,而是要同时查看`/actuator/env`和业务健康检查的结果;而灰度发布时,则会保留5%的流量进行观察10分钟,确认日志中出现`ratio=0.5`的占比已经稳定之后才会全部启动。这样就再也没有出现过“页面已经更新了,但是实例仍然存在的情况”。

结果是:热更新平均需要3到5秒的时间来完成,并且不会超过30秒;由于配置没有被重新加载所导致的回滚次数由原来的每周1到2次降低到现在的0次。有3条经验可以总结出来:第一,@Value并不能代替热更新,单例Bean必须加上@RefreshScope或者换成@ConfigurationProperties;第二,当配置发生变化时要主动去检查一下该bean的本地值是否也跟着变了,并且不能只相信配置中心;第三,在RefreshEvent中把所有的本地缓存、静态Map和连接池参数都清理或者重新配置一遍,否则所谓的“热更新”只是一条消息发出去了,并没有真正起到改变的作用。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。