vlambda博客
学习文章列表

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设计之初本意是来区分环境或者区分租户。

比如应对这两种场景:

  1. 假如公司4套开发环境,dev,test,preprod,prod。那么可以分别建对应4个namespace。
  2. 按照使用nacos的账户来建namespace

官方关于 namespace的定位说明:

https://nacos.io/en-us/blog/namespace-endpoint-best-practices.html

并且namespace之间有严格的引用隔离,即不同namespace的配置不能相互引用,这其实对项目维度的区分带来了很大的不便。

所以,nacos设计者可能最期望的一种使用方式就是,用namespace隔离环境,然后用group来区分项目。

但其实,用惯了appllo后,自然会联想到以几个需求:

  1. 期望每个项目的配置单独管理
  2. 每个应用的配置只能由对应的developer或者最高管理员写。
  3. 实际大部分公司,nacos都不会只搭一套,特别是生产,基本不会和别的环境混用。
  4. 一些公共的通用配置,公司架构的通用约束配置,一个项目多个模块共用的配置,如redis配置,mq配置,swagger开关等。

所以,如果我们按照环境来隔离namespace的话,似乎有些不合适。

并且,nacos现在读写权限只能按照 namespace来分配。

nacos使用体验及避坑指南

所以,要实现第2个需求,就得按 应用去建namespace,这样也似乎合理一些了,并且随之配置文件增多,从控制台的项目分类维度下也能很快找到对应应用配置。

nacos使用体验及避坑指南


为解决公共配置引用的问题,nacos的开发者的回答和建议是:


nacos使用体验及避坑指南

nacos使用体验及避坑指南


也就是说,如果我们按照每个项目建namespace的话,对于公司架构的通用约束配置, 肯定是不同的namespace,所以无法引用,解决办法就是在项目的namespace下再建一份。

那对于同一项目下,多个模块的通用配置,就可以按group去建了,比如建一个 redis-config-group, base-config-group等等。

使用配置中的坑

那按照这个玩法,简单说几点程序使用接入nacos配置中的一些坑。

nacos的配置文件,又分为三个类型:

  • 应用私有配置 (application config)
  • 共享配置 (shared config)
  • 扩展配置 (ext config)

nacos在启动时,会参考bootstrap.yml 文件中的相应配置,依次 加载,共享配置,扩展配置,应用私有配置。

nacos使用体验及避坑指南


然后在,最后其中的load过程,又按逆序做排序

nacos使用体验及避坑指南


所以,最终,这三种类型在spring 容器中的优先级为 应用私有配置 > 扩展配置 > 共享配置。

这个很关键,这影响到我们如何构建我的配置。

在加载应用私有配置文件, nacos的处理:

nacos使用体验及避坑指南


其中,dataIdPrefix,

nacos使用体验及避坑指南


如果,没有在bootstrap.yml中显示指定,会默认取spring.application.name

fileExtension,如果不显示指定,默认为 properties, 所以使用 yml 格式的朋友注意了!!! 必须在bootstrap文件中显示指定spring.cloud.nacos.file-extension属性为yml。

简单配置,保持统一,我们不显示指定dataIdPrefix, 那么,也就是说,你在nacos配置dataid 命名时,必须符合以下之一:

  1. ${spring.application.name}
  2. ${spring.application.name}.${spring.cloud.nacos.file-extension}
  3. ${spring.application.name}.${spring.profiles.active}.${spring.cloud.nacos.file-extension}

而shared config 和 ext config 的坑在于:

nacos使用体验及避坑指南


他们的配置读取会保存在一个单独的静态内部类Config中,这个类中只有属性 dataId, group,  refresh ,也就是说,shared和 ext只能设置这三个属性,并且group和refresh需要单独显示指定。否则默认的 DEFAULE_GROUPfalse 可能会让你吃亏。

此外,因为不支持配置文件格式,所以,需要注意的是,shared和ext的配置文件在创建时,dataId命名必须携带文件格式,并且和bootstrap文件中保持一致。

nacos使用体验及避坑指南


因为这两种文件,解析文件格式的时候,就是以dataId名做的处理,如果像私有配置那样不写文件格式的话,就会按properties文件去解析了,自然就出大错了!

所以,给一份参考配置:



这里,我们是以项目维度去建 namespace,把架构系统通用约束和业务通用配置放在 shared-configs 下。

不过,shared中的group似乎只有个标签的作用,有些鸡肋,因为他还是按照 dataid去单个匹配加载的,并不能说指定某个group下的配置全部加载,并且在配置控制台上也没有直观的分类表现。

但是不同 group下的dataid 是可以重名的,所以,有这方面需求的还是建一个group最好。


最后,因为shared配置优先级低于应用私有配置的原因,如果存在相同的配置,一定是以应用私有配置为主!从继承角度来说,似乎没毛病!