转载

Spring Cloud 配置中心

老司机都喜欢在程序设计中尽可能的把各种参数做成可配置的,等到产品需求发生改动的时候,优雅的修改一行配置,重新加载一次配置,就满足了需求。

配置(Configuration)是不修改代码的情况下,对程序的运行调整的能力。

简单来讲,配置可以分成两类:

  1. 系统配置:包括线程池大小、数据库连接等,变化频率较低
  2. 业务配置:功能开关,功能参数等,变化较为频繁

程序的配置一般而言,分为几个环境:

  1. 开发环境
  2. 测试环境
  3. 生产环境

这几个环境的配置是有差异的,所以配置管理功能应当能够根据当前环境读取对应的配置。

前面提到的不修改代码,只是最低要求,相当多的情况下,程序是不能停机的,这就提出了热更新的需求。

另外,配置的修改应该是有记录可追溯的。

Spring Boot 的配置管理

Spring 实现了非常友好的配置读取方式,

Spring Boot 程序默认使用 application.properties 进行配置。

例如一个参数:

flag=0

在程序中可以通过:

@Value("${flag})
int flag;

来读取。

也可以通过设置多个配置文件:

application.properties
application-dev.properties
application-test.properties
application-prod.properties

application-dev.properties

flag=1

application-test.properties

flag=2

application-prod.properties

flag=3

和在 application.properties 中声明当前的活跃的 profile:

spring.profiles.active=dev

来实现根据运行环境切换配置信息。

以上只是 Spring 强大的配置能力的冰山一角,有兴趣可以参考 外部配置文档 。

这还不够

其实以上描述的 Spring Boot 的配置能力已经很强了,但是有个很致命的问题——无法热更新。

如果非得实现热更新,那可以把配置做成 JSON 文件,再实现一个 endpoint,重新读取一次配置。

假设有一千个实例呢?

Spring Cloud Config

项目 github: https://github.com/spring-cloud/spring-cloud-config

简介:External configuration (server and client) for Spring Cloud

这个项目包含两部分:

  • Server

负责从 git/svn 等版本管理系统中读取配置,并以 http 的方式提供服务。

  • Client

根据客户端配置,从指定的 Server 中读取对应配置,并且与 Spring 本身的 PropertyResource 和 Environment 无缝结合。同时,提供了统一的方式进行配置热更新。

对于这个系统的基础配置和运行,可以参阅下面两个 url:

https://spring.io/guides/gs/centralized-configuration/

http://blog.didispace.com/spring-cloud-starter-dalston-3/

实操进阶

热更新

Spring Cloud Config 实现了非常优雅的热更新。

  • 客户端的配置 Bean 添加 @RefreshScope
@Configuration
@RefreshScope
public class ConsumeConfig {

    @Value("${consume.desc}")
    private String consumeDesc;
    
    @Value("#{'${api.server.round.card}'.split(',')}")
    private List<String> cardList;
}

在配置这个注解之后,调用客户端的 /refresh endpoint,这个 Bean 就会刷新,同时个 Bean 的依赖方下次方法调用时也会更新 Bean 引用。

有些时候,你需要监听这个更新事件,把拿到的最新配置,重新初始化一些部件。那你可以添加:

@EventListener(EnvironmentChangeEvent.class) 这个 annotation。

@Component
public class ConsumeService {

    @Autowired
    ConsumeConfig consumeConfig;

    @EventListener(EnvironmentChangeEvent.class)
    void onEnvChange() {
        //do re-init stuff
    }
}

添加权限

Config Server 任何人都可以通过 http 访问配置,这个不大好,建议加上认证,最简单是使用 Spring-Security 添加一个 basic authentication。

  • 服务器端配置

build.gradle 添加依赖:

dependencies {
    compile('org.springframework.boot:spring-boot-starter-security')
}

application.properties 添加密码(用户名默认是 user):

security.user.password=xxx

重启服务器,再次通过 http 访问配置的时候需要验证。

  • 客户端配置

服务器端做了验证,那客户端也需要添加相应的配置:

bootstrap.yml

spring:
 application:
  name: application
 cloud:
  config:
   uri: http://yourhost.com
   profile: dev
   username: user
   password: xxx

加载多组配置文件

很多时候,为了避免 application.properties 过于臃肿,你可能需要把一些配置文件拆出来,例如专门负责邀请奖励的配置:

invite.properties
invite-dev.properties
invite-test.properties
invite-prod.properties

同样,也区分了多个环境。

那在使用 Spring Cloud 的时候如何读取这个文件呢?

spring:
 application:
  name: application,invite

注意上面的 application.name 是以逗号分隔的两组配置名称。

一些问题

@EventListener 与 SpEL

我在实际使用中发现,在事件监听函数中,使用更新后的配置的时候:

@Value("${consume.desc}")
private String consumeDesc;

@Value("#{'${api.server.round.card}'.split(',')}")
private List<String> cardList;

第一个配置是使用 @Value 绑定一个字符串类型,第二个配置是使用 @Value 中的 SpEL 去将配置中的字符串,切割成 List。

我发现第二个,无法切割成功。试验了多次,还没有找到答案。我已经在 Spring Cloud Config 的 github 上提交了 issue 。

如果有了解这个的,请不吝赐教。

权限管理

在不做二次开发的情况下,这个配置中心的数据是对所有的 client 开放的。某些情况下,这种设定并不合适。

JSON 文件的读取和解析

Spring Cloud Config 本身是可以通过 http 来提供 JSON 文件的访问的,但是Spring Boot 原生并不支持 JSON 配置的读取和解析。

相关选择

其实配置管理工具,选择还是不少的,下面列举一下。

  • owner http://owner.aeonbits.org/

配置文件管理,可以热更新,跟 Spring 没有绑定。

  • cfg4j http://www.cfg4j.org/

专注管理配置文件,也可以实现热更,跟 Spring 没有绑定。

  • applolo https://github.com/ctripcorp/apollo

携程开源的,功能很全

  • disconf https://github.com/knightliao/disconf

百度的一位工程师的开源项目,功能也很全

  • diamond https://github.com/takeseem/diamond

来自阿里的开源,有些日子了

参考文献

http://blog.didispace.com/spring-cloud-starter-dalston-3/

http://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html

http://jm.taobao.org/2016/09/28/an-article-about-config-center/

https://blog.coding.net/blog/spring-cloud-config

本文由kvh 创作,采用 CC BY 3.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。

Spring Cloud 配置中心
原文  http://kvh.io/spring-cloud-config.html
正文到此结束
Loading...