此次我想分享如何管理分布式应用系统中的配置项,咱们的实践与遇到的问题java
我相信你们在开发的过程当中,常常会遇到的问题是git
难道每次配置我都要去代码库中改变而后从新发布版本么?我在曾经的项目中就是这么作的,得益于当时完善的CICD,咱们只须要几分钟就能够完成这样的一次变动,可是依然要面临进程的重启,因此以后的实践中咱们直接将配置管理放入到了编程框架中,并配以中心式的配置管理服务github
我在这篇分享中有大量分享欢迎参考,Go语言分布式系统配置管理实践--go archaius
数据库
有了此次改变后咱们就作到了在运行时让配置生效,不用经过流水线从新发布新版本。apache
在流水线中能作的只是在发布一个服务时,对接配置中心的API,对相关配置进行变动。。好比进行一次新版本的发布,更改金丝雀发布策略。编程
配置中心的数据模型逐渐没法知足需求json
配置项以Dimension划分 Dimension由{service}@{app}#{version}表示,也就是服务相关信息拼接而成的字符串。bash
Dimension就是一个惟一的ID,关联各个配置项,也就是一段json结构体app
{
"timout":"1s",
"pool_size":"10",
}复制代码
也就是说咱们对着微服务,版本,所属应用3个维度来下发信息
负载均衡
若是要更改微服务级别的服务,即不区分版本,咱们就对{service}@{app}这个dimension进行变动。
能力就仅限于这两个层级了。
随着业务的发展咱们发现这样的结构体不能知足一些场景
因为json结构体的局限性配置项的key愈来愈不易理解,key愈来愈长,好比
{
"ServiceB.timeout":"1s",
"ServiceB.user.getUser.timeout":"10",
}复制代码
第一行表示访问服务B时超时是多少
第二行表示到服务B的getUser API超时是多少
这还远远不够,服务还有版本,环境,所属app等多个字段,以下配置,因为每一个字段没有语义,咱们已经没法知道第二个字段究竟是什么意思了。
{
"ServiceB.v1.timeout":"1s",
"ServiceB.user.getUser.timeout":"10",
}复制代码
难道咱们都要继续拼接下去?咱们来看看问题
在发展的过程当中,咱们从新设计了配置中心,不仅围绕微服务场景,或者像kubernetes的config map围绕容器,而是但愿可以成为一个通用的配置中心,让更多的生态接入。
从新设计的结构体。
kie取自key的谐音
正如名字所突出的,key成为了同等公民,一个文件名"xxx,yaml",一个传统的key“timeout” 均可以是一个key,咱们但愿key简单,易理解。而后围绕key定义labels以表示复杂的语义
直接演示下运行效果:
key就在API path中(timeout),label与value在request body中定义
这句话的意思是,在对订单服务进行访问时,超时是1s
返回的respsonse body中,能够看到版本号“revision”是2,这说明,label是第二次被使用(之间labels的历史记录已经被储存了)
value具有type,不传就是plain text,在前台显示是能够根据类型作展现,更易读
最重要的是labels,你能够为key定义多个labels,只有label彻底一致,才认为这是个惟一的“Dimension”,我用label概念来代替了过去定死的Dimension。有了labels与key,你已经能够自由的去定义本身的配置,表达本身的语义
我接着新建了一个配置,表示访问该服务,要使用会话粘纸,可是能够看到,revison是3,由于历史管理是根据label记录的,以让用户能够根据labels来将全部key快速回滚到某个历史状态中,单一的回滚key来试图恢复系统也许会引发更大的混乱。
咱们再来个稍微复杂的
此次咱们新建了一个复杂语义的label,表示:若是前台访问订单服务的1.0.1,那么负载均衡策略是round robin。
今天的介绍就简单到这里,后面会持续对kie的新特性进行分享,经过这篇我但愿经过分享让你们对复杂分布式系统中的配置管理实践有些了解。