Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[discuss]: nacos config support sharing configuration with multi Applications #141

Open
pbting opened this Issue Dec 5, 2018 · 12 comments

Comments

Projects
None yet
7 participants
@pbting
Copy link
Collaborator

pbting commented Dec 5, 2018

SCA Nacos Config 共享配置方案设计

随着社区的回馈,发现 Spring Cloud Alibaba Nacos Config Starter 目前不能完美的来支持多个应用间的一些共享配置。
在实际的业务场景中应用和共享配置间的关系可能如下图所示:

应用的配置关系

  • 从单个应用的角度来看: 应用可能会有多套(develop/beta/product)发布环境,多套发布环境之间有不同的基础配置,例如数据库。
  • 从多个应用的角度来看:多个应用间可能会有一些共享通用的配置,比如多个应用之间共用一套zookeeper集群。

目前 SCA Nacos Config 可以灵活的支持单个应用间在多套环境可灵活的切换,但是在多个应用间共享一些通用的配置支持的还不是很完美。
本方案设计的目标就是来解决这个问题。目前有三种设计方案,分别是:

  • 新增一个应用分组的配置,分组命名的格式是 通过域名的命名方式,来自动的生成共享配置的 Data Id。
  • 自定义命名的方式来命名 Data Id 。
  • 通过类似面向对象的方式自定义配置(相对于第二种的升级版)。

下面分别来分析三种方案的具体实现和优缺点。

基于域名的配置方式给应用分组

通过一个配置参数(例如:${spring.application.group}) 来指明当前应用所属的分组(或者说所属的域)。
例如我有两个应用分别为Order_Application和Auth_Application,给这两个应用配置的分组名(域)是:

spring.application.group=com.alibaba.aliware.edas

那对于Spring Cloud Alibaba Nacos Config 来说,多个应用可以属于 com.alibaba 这个应用分组(域),也可以属于
com.alibaba.aliware 这个应用分组(域),当然也可以属于 com.alibaba.aliware.edas 这个应用分组(域)。
罗里吧嗦了这么多,目的就是 Data Id 通过以这个分组(域)来命名,从而实现多个应用间在某个分组(域)下的共享配置。如下图所示:

多应用间的配置关系

以这种方式来实现多个应用间的配置共享,可以看出他具有天然的局限性。

  • 受到 ${spring.application.group }配置的影响,Data Id 的表现力是非常有限的(当然85%的场景应该够用了)。

    • 一方面是Data Id 的命名个数受到了限制。
    • 另一方面如果两个应用的 file-extension 不一致(一个是properties,一个是yaml),那这个时候共享配置的Data Id 必须同时要含有 properties 和 yaml 为扩展名的配置。
    • Data Id 的命名也受到了 ${spring.application.group } 配置的束缚。
  • 学习成本偏高(当然还是可以学会的)。学习成本偏高体现在:

    • 要知道Data Id 的命名规则,才能在项目实施过程中对 Data Id 的命名运用自如。
    • 此外对于域名命名的层次个数也不太好把握。少了的话,担心dataid的个数不够用,多了的话看上去有显得的比较冗余。
    • 还需要学习并理解这里配置的优先级,不然在程序中有可能就会拿到意想不到的配置。
  • 易出错(当然是可以克服的)。对于多级应用分组的配置共享,这个时候Data Id 的命名要格外注意了。注意他们的层次关系,Data Id 书写时不要张冠李戴。

  • 实现起来稍微复杂

当然他的好处也非常明显,当你理解了他背后的设计理念时,这个共享配置的层次也非常明显。因为层次的关系天然依托于域名的层次关系。

自定义的方式来命名 Data Id

这种方式实现简单易懂,即 SCA Nacos Config 会新增加一个配置,用来配置可实现共享配置所有的 Data Id。如下所示:

spring.cloud.nacos.shared.dataids=global.yaml,app-common.yaml,app-local-common.yaml

NOTE: 为了尽可能的和Nacos使用方式(即Data Id 是一个带有额外文件扩展名的)保持一致,这里配置的Data Id 是一定需要带上文件扩展名的。

这个时候两个应用(或多个应用)之间共享配置的 Data Id 关系如下图所示:

Spring Boot 提倡约定大于配置。当使用这种方式来实现应用间的共享配置时,我们也继承了Spring Boot的这个优良传统,多个共享配置间的一个优先级的关系我们约定:按照配置出现的先后顺序,即后面的优先级要高于前面的。
这种方式的优点在于:

  • dataid的命名方式完全交给业务方本身,不受 SCA Nacos Config Starter 实现的束缚。
  • dataid的命名方式既可以参考第一种方式来命名,又可以充分的发挥主观能动性,结合自己实际的业务给dataid命名。
  • 减少了多个应用间如果file-extension不一致,为每个 file-extension 多加这么一个配置的麻烦。
  • 当使用这种方式时,不会为这些共享配置强制绑定一个 file-extenson,即可以直接在我们暴露出来的一个变量中 dataid以file-extension 结尾。如果没有显示的说明,这个时候就会以file-extenson为准。

当然这种方案的缺点在于扩展性不强。即如果对于某个共享配置需要做额外的配置,例如额外配置Group/是否需要刷新/是否需要从本地缓存加载等等。因此为了应对这种类型的场景,小组内讨论出了第三种方案。

通过类似面向对象方式的自定义配置

说明: Spring 可以支持在加了 ConfigurationProperties 注解配置类的内部某个对象实例来注入应用中的一些配置。

这种使用方式查了一下官方和网络上没有一个大的标题总结,结合这种方式很像给某个实例中的字段赋值,所以这里先暂时取名:
类似面向对象方式的自定义配置(有更好能够形象的标明其含义的命名可以在下面留下评论-_-)。

这种方案沿用了第二种设计方案的优点,同时又弥补了第二种方案的不足。我们通过内部定义一个对象,来支持一些灵活的扩展配置。
我们给这个对象可以预留一些可扩展的配置字段。例如:

public class Config{
    private String dataId;
    private String group = "DEFAULT_GROUP";
    private Boolean refresh = false;
    //.....后期可能还有其他的一些配置

    //省略 set/get 方法
}

最终在实现时是可以支持以list的方式来配置其值。如下是两个扩展配置的实例:

spring.cloud.nacos.config.ext-config[0].data-id=global-shared.properties # group 和referesh 使用默认值
spring.cloud.nacos.config.ext-config[1].data-id=app-common.properties
spring.cloud.nacos.config.ext-config[1].group=DEVELOP_GROUP #配置自定义所在的组
spring.cloud.nacos.config.ext-config[1].refresh=true #需要刷新

NOTE: 为了尽可能的和Nacos使用方式(即data id是一个带有额外文件扩展名的)保持一致,这里配置的dataid是一定需要带上文件扩展名的。

最终的实现

SCA Nacos Config 在第二种方案和第三种方案的实现上是并存的。如果你觉得第三种方案配置的比较麻烦,同时第二种方案就可以满足你的需求,这个时候就可以选择第二种方案。
如果你需外可读性好、层级感比较明显、后期的扩展性更强,那这个时候第三种方案也是OK的。

@qiumingbao

This comment has been minimized.

Copy link

qiumingbao commented Dec 5, 2018

第二种方式可读性更好,同时通过手工指定,可以灵活控制不同版本之间配置共存的情况。第三种方式略复杂,同时会否影响性能。

@fudali113

This comment has been minimized.

Copy link

fudali113 commented Dec 5, 2018

我认为是不是有一种可以在配置在增加相关配置的功能,比如可能因为一些原因我需要给我的信用添加相似的配置,但是它可能也是比较独立的一块。

如果这个样子我们增加一个文件,然后在去项目里面增加一个这个文件的配置,这样子项目多了修改的成本就会比较高。

那是不是在我们项目dataid指定的配置里添加某种还可以再加载一次外部配置的功能,我们就可以在外部有一个统一修改的地方。这样子会不会带来更方便的扩展性?

@universefeeler

This comment has been minimized.

Copy link

universefeeler commented Dec 5, 2018

比较支持第一种方式,在应用较多的时候优势明显;另外,层次性更好,合理命名会具备很强的自解释性;另外更符合一般通用配置思维

@pbting

This comment has been minimized.

Copy link
Collaborator Author

pbting commented Dec 6, 2018

第二种方式可读性更好,同时通过手工指定,可以灵活控制不同版本之间配置共存的情况。第三种方式略复杂,同时会否影响性能。

第三种方式相对于第二种来说确实稍微复杂了那么一点。但是性能的话 可以具体说下哪里会影响到性能?我理解这里只是表现形式上的不一样,做监听取数据都是一样的,同时这也是在应用启动的时候执行。所以没太明白你指的会影响性能是指?

@pbting

This comment has been minimized.

Copy link
Collaborator Author

pbting commented Dec 6, 2018

我认为是不是有一种可以在配置在增加相关配置的功能,比如可能因为一些原因我需要给我的信用添加相似的配置,但是它可能也是比较独立的一块。

如果这个样子我们增加一个文件,然后在去项目里面增加一个这个文件的配置,这样子项目多了修改的成本就会比较高。

那是不是在我们项目dataid指定的配置里添加某种还可以再加载一次外部配置的功能,我们就可以在外部有一个统一修改的地方。这样子会不会带来更方便的扩展性?

我理解下来你的意思是不是希望可以加载只要匹配 application-*.properties 类型的data id 都可以动态加载。那这个时候再加一个 这种类型的配置就不要手动的去应用配置文件中指定需要加载的dataid了, 是吗?

@pbting

This comment has been minimized.

Copy link
Collaborator Author

pbting commented Dec 6, 2018

比较支持第一种方式,在应用较多的时候优势明显;另外,层次性更好,合理命名会具备很强的自解释性;另外更符合一般通用配置思维

同意楼主上面的观点,但是他的局限性也是比较明显,限制比较多。

@fudali113

This comment has been minimized.

Copy link

fudali113 commented Dec 6, 2018

我认为是不是有一种可以在配置在增加相关配置的功能,比如可能因为一些原因我需要给我的信用添加相似的配置,但是它可能也是比较独立的一块。
如果这个样子我们增加一个文件,然后在去项目里面增加一个这个文件的配置,这样子项目多了修改的成本就会比较高。
那是不是在我们项目dataid指定的配置里添加某种还可以再加载一次外部配置的功能,我们就可以在外部有一个统一修改的地方。这样子会不会带来更方便的扩展性?

我理解下来你的意思是不是希望可以加载只要匹配 application-*.properties 类型的data id 都可以动态加载。那这个时候再加一个 这种类型的配置就不要手动的去应用配置文件中指定需要加载的dataid了, 是吗?

应该有一些差别,我不希望通过范匹配来进行一个数据的拉取,我希望所有的配置拉取都是明确的,这也是我不太认可第一种方案的原因之一;

我的意思大概是这个样子的:
比如我的应用配置是这个样子的:

spring.cloud.nacos.shared.dataids=global.yaml,app-common.yaml,app-local-common.yaml

然后我的app-common.yaml 配置是这个样子的:

include-dataids:
- xxx.yaml

那么最终 xxx.yaml 也会加载成为我应用的配置,xxx.yaml的优先级比 include 他的配置文件(app-common.yaml) 优先级略低,但是优先级高于基础配置中比 app-common.yaml 优先级更低的配置 global.yaml ;

所有的 dataId 都是必须手动制定的,虽然范匹配和基于一定规则匹配会带来一定的遍历性,但是也可能在某些时候带来一定的不确定性(比如配置的人还不太熟悉该规则?或者是一时忘记了某种规则?)

更简洁一些的方案

同时,以上只是基于第二种方案提出的,在于优先级的处理上可能会有些复杂,那是不是也可以简单点的定义为在应用基础配置中只能配置一个 dataId: app-local-common.yaml,然后在 app-local-common.yaml 中去做 include 的操作?

想法的来源

我的方案大致来自于我的两个对于配置中的诉求:

  • 所有配置的加载必须明确指定;(范匹配带来便利,但是需要对规则高度熟悉;对人的要求比较高,但是并不是所有人都优秀)
  • 我们应该尽可能的把配置交给配置中心处理;(这也是我们需要配置中心的理由,使用配置中心就是为了把配置独立出去;除了应用与配置的关联,我觉得其他的配置都应该交给配置中心)

@pbting

@pbting

This comment has been minimized.

Copy link
Collaborator Author

pbting commented Dec 7, 2018

include-dataids

恩有道理。这个方案算是相对于第二种和第三种的一个补充。即在dataid 暴露出来给业务方自己配置的同时,又支持在配置里面显示的说明需要 include-dataids。那这个时候就我理解就相当于在你们的配置里面需要指明SCA Nacos Config 能够识别的一个 key,才可以去加载。

可以给我们提个feature。

@fudali113

This comment has been minimized.

Copy link

fudali113 commented Dec 8, 2018

怎么提 feature 啊? 再开一个 issue ? @pbting

@pbting

This comment has been minimized.

Copy link
Collaborator Author

pbting commented Dec 10, 2018

怎么提 feature 啊? 再开一个 issue ? @pbting

是的,issue 开头用 [feature] 标明即可。感谢..

@xujingle1995

This comment has been minimized.

Copy link

xujingle1995 commented Jan 22, 2019

请问各位大佬,第一种“基于域名的配置方式给应用分组”,为什么我配置了spring.application.group=com.alibaba.aliware.edas,在nacos server创建了com.alibaba:application.properties/com.alibaba.aliware:application.properties/com.alibaba.aliware.edas:application.properties三个配置文件,然而并不起效果?工程启动依然会去nacos上寻找${spring.application.name}.properties,找不到就直接报错?group和命名空间都没问题。我用的0.2.1.RELEASE版本的,Nacos Server 0.7.0版本

@gumutianqi

This comment has been minimized.

Copy link

gumutianqi commented Feb 11, 2019

请问目前Nacos 的实现情况是怎么样的呢,求应用共享配置 example project.

@fangjian0423 fangjian0423 added the nacos label Mar 19, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.