nacos使用体验及避坑指南
❝统一配置中心,作为微服务治理的关键组件,社区上也有很多选型:spring cloud官方的 sping-cloud-config, 百度的disconf, 阿里的nacos,携程的apollo。
几年前因为部门开发需要,有负责过统一配置中心的技术选型调研,从满足我们的实际需求出发,最终选择了apollo。(实际上,当时公司内部有自研的ducc,听过内部分享,很强大,不过因为需要私有部署还有开发语言的原因,最终还是打算选择开源框架)
现在新公司因为用spring cloud alibaba作为微服务框架的原因,自然选择了本家的nacos作为我们的统一配置中心。
设计亮点
在使用了一段时间后,发现了不少nacos不同于apollo的设计亮点。
亮点一:既是配置中心也是注册中心
其实,这也是合理的,注册中心的最关键作用,就是通过长连接的方式或者rpc定时心跳的方式来及时通知接入方配置信息的变更,
服务的注册信息,也是一种需要及时同步的配置信息。还有像其实 zookeeper,etcd不只是注册中心,也有人当做配置工具玩。
而apollo只是单一的配置中心功能,为了自身的高可用,apollo内部又用了eruaka来注册管理各个apollo server节点。
从这个角度来看,nacos高明多了,运维成本低很多。
不过凡事看实际需求,我们当初选项apollo的时候,nacos开源不久,相对不成熟。并且我们完全exclude了spring cloud的相关组件,有公司现有适用的一套微服务治理解决方案。
亮点二:spring cloud 支持友好
如果开发框架是spring cloud, 天然配置支持方式很友好。apollo的话其实倒也还好,不过一般会再自己封starter来简化接入。
亮点三:配置更新机制
或者说争议点,我们开发使用spring框架,自然希望配置更新后,spring 容器中也能及时更新。
apollo对于@Value
引用配置,会自动更新spring容器相应的值。但是nacos不是,@Value
同时需要搭配Spring cloud的@RefreshScope()
注解,通过spring cloud bus来更新容器值(实际apollo也是利用的spring cloud的配置刷新机制,不过监听到变化后,自动处理了), 或者用nacos自己的注解 @NacosValue
。
见仁见智,我投nacos一票,因为并不是所有的配置都需要实时更新,为了防止误操作,导致线上出问题,在指定需要的服务上面通过指定注解来开启,似乎是个解决方案。
亮点四:yml 格式校验比较完善
yml格式对于spring boot开发者来说,是一个比较习惯的配置格式。
我当时使用的apollo版本,对yml和yaml格式的校验都不太友好,假如你的公司对线上配置权限比较严格,只允许ops来操作,那很容易出现线上配置出错。
nacos在配置完毕,提交时,会提醒你,哪块语法有问题。
不过属于前端校验的问题,apollo现在的版本应该可以解决。
不友好的点
但是,相比于apollo,直观清晰的先建应用,再建应用下的配置,还有可继承公共配置的特点来说,nacos不太友好。
简单描述一下nacos的一些设计理念:
nacos 配置文件的组织方式为:
如图,nacos中配置文件组织由大到小为 namespace > group > data id。
每个配置文件必须有唯一的dataid,nacos中的namespace设计之初本意是来区分环境或者区分租户。
比如应对这两种场景:
-
假如公司4套开发环境,dev,test,preprod,prod。那么可以分别建对应4个namespace。 -
按照使用nacos的账户来建namespace
官方关于 namespace的定位说明:
https://nacos.io/en-us/blog/namespace-endpoint-best-practices.html
并且namespace之间有严格的引用隔离,即不同namespace的配置不能相互引用,这其实对项目维度的区分带来了很大的不便。
所以,nacos设计者可能最期望的一种使用方式就是,用namespace隔离环境,然后用group来区分项目。
但其实,用惯了appllo后,自然会联想到以几个需求:
-
期望每个项目的配置单独管理 -
每个应用的配置只能由对应的developer或者最高管理员写。 -
实际大部分公司,nacos都不会只搭一套,特别是生产,基本不会和别的环境混用。 -
一些公共的通用配置,公司架构的通用约束配置,一个项目多个模块共用的配置,如redis配置,mq配置,swagger开关等。
所以,如果我们按照环境来隔离namespace的话,似乎有些不合适。
并且,nacos现在读写权限只能按照 namespace来分配。
所以,要实现第2个需求,就得按 应用去建namespace,这样也似乎合理一些了,并且随之配置文件增多,从控制台的项目分类维度下也能很快找到对应应用配置。
为解决公共配置引用的问题,nacos的开发者的回答和建议是:
也就是说,如果我们按照每个项目建namespace的话,对于公司架构的通用约束配置, 肯定是不同的namespace,所以无法引用,解决办法就是在项目的namespace下再建一份。
那对于同一项目下,多个模块的通用配置,就可以按group去建了,比如建一个 redis-config-group, base-config-group等等。
使用配置中的坑
那按照这个玩法,简单说几点程序使用接入nacos配置中的一些坑。
nacos的配置文件,又分为三个类型:
-
应用私有配置 (application config) -
共享配置 (shared config) -
扩展配置 (ext config)
nacos在启动时,会参考bootstrap.yml 文件中的相应配置,依次 加载,共享配置,扩展配置,应用私有配置。
然后在,最后其中的load过程,又按逆序做排序
所以,最终,这三种类型在spring 容器中的优先级为 应用私有配置 > 扩展配置 > 共享配置。
这个很关键,这影响到我们如何构建我的配置。
在加载应用私有配置文件, nacos的处理:
其中,dataIdPrefix,
如果,没有在bootstrap.yml中显示指定,会默认取spring.application.name
。
fileExtension,如果不显示指定,默认为 properties, 所以使用 yml 格式的朋友注意了!!! 必须在bootstrap文件中显示指定spring.cloud.nacos.file-extension属性为yml。
简单配置,保持统一,我们不显示指定dataIdPrefix, 那么,也就是说,你在nacos配置dataid 命名时,必须符合以下之一:
-
${spring.application.name} -
${spring.application.name}.${spring.cloud.nacos.file-extension} -
${spring.application.name}.${spring.profiles.active}.${spring.cloud.nacos.file-extension}
而shared config 和 ext config 的坑在于:
他们的配置读取会保存在一个单独的静态内部类Config中,这个类中只有属性 dataId, group, refresh ,也就是说,shared和 ext只能设置这三个属性,并且group和refresh需要单独显示指定。否则默认的 DEFAULE_GROUP
和 false
可能会让你吃亏。
此外,因为不支持配置文件格式,所以,需要注意的是,shared和ext的配置文件在创建时,dataId命名必须携带文件格式,并且和bootstrap文件中保持一致。
因为这两种文件,解析文件格式的时候,就是以dataId名做的处理,如果像私有配置那样不写文件格式的话,就会按properties文件去解析了,自然就出大错了!
所以,给一份参考配置:
这里,我们是以项目维度去建 namespace,把架构系统通用约束和业务通用配置放在 shared-configs 下。
不过,shared中的group似乎只有个标签的作用,有些鸡肋,因为他还是按照 dataid去单个匹配加载的,并不能说指定某个group下的配置全部加载,并且在配置控制台上也没有直观的分类表现。
但是不同 group下的dataid 是可以重名的,所以,有这方面需求的还是建一个group最好。
最后,因为shared配置优先级低于应用私有配置的原因,如果存在相同的配置,一定是以应用私有配置为主!从继承角度来说,似乎没毛病!