2018-10-17 · Develop

Java 配置文件-环境隔离和分布式配置中心选型

前面我们已经实现了使用 Java 流读取配置文件和使用 Spring 加载配置的4种姿势。
下面讲述下在项目的增长种遇到的几种需求以及解决方案。

环境隔离

我们在进行业务的开发过程中,一般都会有多个环境,比如:开发、测试、线上等。对于不通环境的配置肯定会有不通的地方,比如数据库的连接配置等。解决的方案也是多样的:

Maven 环境隔离

如果你的系统是使用 maven 来管理依赖的话,可以使用 Maven 的环境隔离(profile)来解决。
Maven 的环境隔离方式可以参考 《Maven 实战》或者英文版的 《Maven in Action》 里面14章讲解的使用 profile 实现环境差异性的构建。

针对不同环境的 profile

<!-- Maven 环境隔离 -->
<profiles>
    <!--开发环境-->
    <profile>
        <id>dev</id>
        <properties>
            <deploy.type>dev</deploy.type>
        </properties>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>        
    </profile>
    <!--测试环境-->
    <profile>
        <id>test</id>
        <properties>
            <deploy.type>test</deploy.type>
        </properties>
    </profile>
    <!--线上环境-->
    <profile>
        <id>prov</id>
        <properties>
            <deploy.type>prov</deploy.type>
        </properties>
    </profile>
</profiles>

以上代码可以添加到项目 pom.xml 文件中,也可以用来控制多项目的 settings.xml 文件。上面代码的意思是在 properties 中设置了个 deploy.type 变量,变量的值随着 profile 的激活情况而变化。

创建各个环境的配置文件

那我们如何使用上面第一的 deploy.type 变量来控制配置文件的内容呢。其实就是将不通的配置放在不同的文件夹下面,这个变量就是控制的文件夹的名称,创建如下的文件路径:

+--- pom.xml
+--- src
|   +--- main
|   |   +--- java
|   |   |   +--- com
|   |   +--- resources
|   |   +--- resources.env
|   |   |   +--- dev
|   |   |   |   +--- datasources.properties
|   |   |   +--- prov
|   |   |   |   +--- datasources.properties
|   |   |   +--- test
|   |   |   |   +--- datasources.properties
|   |   +--- webapp
|   |   |   +--- WEB-INF
|   |   |   |   +--- web.xml

我们在 resources.env 文件夹下面创建了和 deploy.type 变量相同值得文件夹,然后放入各个环境得 datasources.properties 配置文件。可以 resources.env 不是 maven 的标准目录结构,我们在项目的 pom.xml 还需配置 maven 的目录结构。

<resources>
    <resource>
        <directory>src/main/resources.env/${deploy.type}</directory>
    </resource>
    <resource>
        <directory>src/main/resources</directory>
    </resource>
</resources>

这样 maven 在打包的时候会使用把 resources 和 resources.env/${deploy.type} 两个文件夹下面的文件 copy 到 classes 目录下。

打包部署

上面配置的默认激活的 profile ID 是 dev ,如果你需要其他如 prov 的处于激活状态的话可以使用如下命令打包

mvn clean package -Dmaven.test.skip=true -Pprov

通过 -P 命令传入 prov 参数, mvn 在打包的时候激活 ID 为 prov 的 profile,使得变量 deploy.type 的值为 prov,所以将 resources.env/prov/ 下面的文件 copy 到 classes 目录下。

SpringBoot 环境隔离

SpringBoot 提供了一种环境隔离的方式,只需要创建 application-{profile}.yml 文件即可,其中的 {profile} 就是环境ID。就像如下的文件列表

application-dev.yml     # 开发环境
application-test.yml    # 测试环境
application-prov.yml    # 生成环境

在启动的时候只需要加上环境选择的启动参数就行了:

java -jar -Dspring.profiles.action=dev target/app-1.0-SNAPSHOT.jar

或者在 application.yml 中配置:

spring:
  profiles:
    active: dev

分布式配置中心

随着项目的增多,比如现在有100的项目,每个项目都配置3个环境,各个开发人员给 profile 的ID名取得不一样,有的叫 dev 而有的叫 develop。这样得话却增加了运维小哥得负担,需要更加环境常见不同的自动化集成。而且线上配置也在项目中,对所有人员开放。这就暴露出传统的配置方式的弊端,比如:历史版本控制、权限控制、安全控制等问题。
而配置中心就是解决这类问题而出生的,配置中心来统一管理配置!把业务开发者从复杂以及繁琐的配置中解脱出来,只需专注于业务代码本身,从而能够显著提升开发以及运维效率。

配置中心的演变过程

此处的演变过程借鉴微信公众号 Java后端技术

distributed-config-center-1

这样的设计瓶颈就是每次配置的读取都会进行 rpc 请求。

distributed-config-center-2

相对与上面的设计增加了对本地缓存的设计,这样就减少 rpc 调用。但是对于数据 CAP 原理,这种方式只做到了 AP ,只是保证了数据的最终一致性,配置的更改会有一段时间的不一致。

distributed-config-center-3

这里引入消息队列或者 ZooKeeper 在修改了配置的时候及时更新数据,这样就保证了数据的实时性。

开源项目的选择

在技术选型时,你得知道各个开源项目的差异性才好选型。这里记录下各个分布式配置中心开源项目的特点,以备后面使用。

Apollo

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

apollo-overall-architecture

XDiamond

全局配置中心,存储应用的配置项,解决配置混乱分散的问题。名字来源于淘宝的开源项目diamond,前面加上一个字母X以示区别。

xdiamond-profile

QConf

QConf 是一个分布式配置管理工具。 用来替代传统的配置文件,使得配置信息和程序代码分离,同时配置变化能够实时同步到客户端,而且保证用户高效读取配置,这使的工程师从琐碎的配置修改、代码提交、配置上线流程中解放出来,极大地简化了配置管理工作。

q-conf

Disconf

专注于各种「分布式系统配置管理」的「通用组件」和「通用平台」, 提供统一的「配置管理服务」。

disconf

disconf-flow

Spring Cloud Config

spring-cloud-config

他们的主要区别:

distributed-config-center-compare


参考文档:
为什么需要分布式配置中心?