如需为部署在多台服务器的应用更改配置,在各台服务器上逐一更改显然效率太低。您可以使用ACM集中管理配置。ACM会将更新后的配置动态推送到所有服务器。本文结合具体场景介绍此操作流程。

前提条件

  • 已开通ACM服务。
  • 服务器上已安装JDK,并已设置环境变量JAVA_HOME
  • 服务器上已安装Maven。关于如何安装和使用Maven,请参考Maven官方文档

背景信息

在传统的配置发布模式下,如果一个应用部署在多台服务器上,配置变更就需要再在所有服务器上逐一更改,效率低且工作繁琐。

您可以在ACM中简化此操作。首先您需要在ACM中为应用创建配置,并在应用中使用ACM的原生API监听此配置的变更。当您在ACM控制台更改此配置后,所有部署了该应用的服务器都会收到变更后的配置内容,应用状态也会随之刷新。

以下使用示例场景进行说明。

应用myapp.jar部署在生产环境的两台服务器上。该应用包含一个配置文件app.cfg,该配置文件包含线程池大小threadPoolSize和日志级别logLevel这两个配置项。现在需要同时调整该应用在上述两台服务器上的配置,并动态刷新应用的状态。

图 1. 示例场景:通过ACM动态推送配置
通过ACM动态推送配置

步骤一:在ACM中创建配置

  1. 登录ACM控制台,在顶部菜单栏选择地域。
  2. 在左侧导航栏选择配置列表,在页面上方选择命名空间,然后在页面左侧单击创建配置
    创建配置
  3. 在弹出的创建配置面板中填写配置信息,配置完成后单击创建
    创建配置
    参数描述
    Data ID配置ID。建议采用package.class的命名规范,其中class部分是具有业务含义的配置名称,例如:com.foo.bar.log.level。Data ID在一个Group下是唯一的。
    Group配置分组,建议填写产品名或模块名。Group是全局唯一的。
    数据加密您可完成如下配置来统一使用密钥管理服务(KMS)对配置进行加密:
    1. 打开数据加密
    2. 数据加密区域单击前往授权
    3. 云资源访问授权页面选择AliyunACMAccessingKMSRole并单击同意授权
    4. 刷新创建配置面板,选择KMS加密方式。
    配置格式配置内容的数据格式。
    配置内容输入配置的内容,例如:
    threadPoolSize=5
    logLevel=WARN
    配置描述配置描述信息。
    更多配置
    • 应用:配置归属的应用名。
    • 标签:在文本框中输入标签信息,并单击标签选择器。

步骤二:使用ACM原生API监听配置变更

  1. 下载样例工程myapp.zip,或者运行以下命令来创建Maven工程。
    mvn archetype:generate -DgroupId=com.acm.sample -DartifactId=myapp -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

    创建的工程结构如下:

    myapp
    |-- pom.xml
    `-- src
        |-- main
        |   `-- java
        |       `-- com
        |           `-- acm
        |               `-- sample
        |                   `-- App.java
        `-- test
            `-- java
                `-- com
                    `-- mycompany
                        `-- app
                            `-- AppTest.java
  2. 在pom.xml中添加对ACM Client原生API的依赖。
    <dependencies>
         <dependency>
             <groupId>com.alibaba.edas.acm</groupId>
             <artifactId>acm-sdk</artifactId>
             <version>1.0.9</version>
         </dependency>
         <!-- 如果已有日志实现,则可去除以下依赖 -->
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
             <version>1.1.7</version>
         </dependency>
     </dependencies>
  3. 在pom.xml中添加maven-assembly-plugin打包插件。
    <plugin>
       <artifactId>maven-assembly-plugin</artifactId>
       <version>2.4</version>
       <configuration>
          <finalName>myapp</finalName>
          <descriptorRefs>
             <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <appendAssemblyId>false</appendAssemblyId>
          <archive>
             <manifest>
                <mainClass>com.acm.sample.App</mainClass>
             </manifest>
          </archive>
       </configuration>
       <executions>
          <execution>
             <id>make-assembly</id>
             <phase>package</phase>
             <goals>
                <goal>single</goal>
             </goals>
          </execution>
       </executions>
    </plugin>
  4. 使用ACM Client原生API监听配置变更。
    说明 以下代码中的$endpoint$namespace$accesskey$secretKey等变量的值,可在ACM控制台的配置列表页面获取和查看。 查看参数信息
    //-- App.java
    package com.acm.sample;
    
    import java.io.IOException;
    import java.io.StringReader;
    import java.util.Properties;
    import com.alibaba.edas.acm.listener.ConfigChangeListener;
    import com.alibaba.edas.acm.ConfigService;
    import com.alibaba.edas.acm.exception.ConfigException;
    
    public class App {
    
         private static Properties appCfg = new Properties();
    
         public static void initAndWatchConfig() {
             final String dataId = "com.acm.myapp.app.cfg";
             final String group = "myapp";
             final long timeoutInMills = 3000;
    
             // 从命名空间详情对话框中拷贝各变量的值Properties properties = new Properties();
             properties.put("endpoint", "$endpoint");
             properties.put("namespace", "$namespace");
    
             // 如果通过AK/SK访问ACM
             properties.put("accessKey", "$accessKey");
             properties.put("secretKey", "$secretKey");
    
             // 如果通过ECS实例RAM角色访问ACM
             // properties.put("ramRoleName", "$ramRoleName");
    
             // 如果是加密配置,则添加以下两行进行自动解密
             // properties.put("openKMSFilter", true);
             // properties.put("regionId", "$regionId");
    
             ConfigService.init(properties);
    
             // 直接获取配置内容try {
                 String configInfo = ConfigService.getConfig(dataId, group, timeoutInMills);
                 appCfg.load(new StringReader(configInfo));
             } catch (ConfigException e1) {
                 e1.printStackTrace();
             } catch (IOException e) {
                 e.printStackTrace();
             }
    
             // 监听配置变化,获取最新推送值ConfigService.addListener(dataId, group, new ConfigChangeListener() {
                 public void receiveConfigInfo(String configInfo) {
                     try {
                         appCfg.load(new StringReader(configInfo));
                     } catch (Exception e) {
                         // process exception
                     }
                     refreshApp();
                 }
             });
         }
    
         public static void refreshApp() {
             System.out.println("current thread pool size: " + appCfg.getProperty("threadPoolSize"));
             System.out.println("current log level: " + appCfg.getProperty("logLevel"));
             System.out.println("");
         }
    
         public static void main(String[] args) {
             initAndWatchConfig();
    
             // 以下代码用于测试,作用是让主线程不退出。订阅配置是守护线程,如果主线程退出守护线程就会退出。while (true) {
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                 }
             }
         }
     }

步骤三:部署并启动应用

  1. 在项目根目录执行以下打包命令,将应用打包成JAR文件,并拷贝到两台服务器上。
    mvn clean package
  2. 在Shell中部署并启动应用。
    ${JAVA_HOME}/java -cp myapp.jar com.acm.sample.App

步骤四:在ACM控制台更改配置

  1. 登录ACM控制台,在顶部菜单栏选择地域。
  2. 在左侧导航栏选择配置列表,在配置列表页面选择创建的配置,然后在操作列单击编辑
  3. 编辑配置页面上将配置内容更改为以下内容,并单击发布
    threadPoolSize=15
    logLevel=DEBUG
  4. 内容比较对话框中查看更改前后的对比,确认无误后单击发布

执行结果

发布配置之后,部署了myapp应用的两台服务器均收到了更新后的配置,并在Console中打印了以下日志。

current thread pool size: 15
current log level: DEBUG