Spring Cloud 学习教程——第六篇:统一配置中心(Spring Cloud Config)

一、简介

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件spring cloud config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。在spring cloud config 组件中,分两个角色,一是config server,二是config client。

随着线上项目变的日益庞大,每个项目都散落着各种配置文件,如果采用分布式的开发模式,需要的配置文件随着服务增加而不断增多。某一个基础服务信息变更,都会引起一系列的更新和重启,运维苦不堪言也容易出错。配置中心便是解决此类问题的灵丹妙药。

市面上开源的配置中心有很多,BAT每家都出过,360的QConf、淘宝的diamond、百度的disconf都是解决这类问题。国外也有很多开源的配置中心Apache的Apache Commons Configuration、owner、cfg4j等等。

二、配置中心提供的核心功能

  • 提供服务端和客户端支持
  • 集中管理各环境的配置文件
  • 配置文件修改之后,可以快速的生效
  • 可以进行版本管理
  • 支持大的并发查询
  • 支持各种语言

Spring Cloud Config可以完美的支持以上所有的需求。

Spring Cloud Config项目是一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。Spring cloud使用git或svn存放配置文件,默认情况下使用git,我们以git为例。

首先在github上面创建了一个文件夹 config-files用来存放配置文件,为了模拟生产环境,我们创建以下三个配置文件:

// 开发环境
mengma-config-dev.yml
// 测试环境
mengma-config-test.yml
// 生产环境
mengma-config-pro.yml

每个配置文件中都写一个属性 hello ,属性值分别是 mengma.....dev / mengma.....test / mengma.....pro 。下面我们开始配置config server 端。

config server 端代码编写

  • 新建项目,引入依赖,只需要引入 config -server 就可以 ,不需要引入 eureka-client ,web

config-server

  • 配置配置文件
server:
  port: 8778
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/***    #  配置git仓库的地址
          search-paths: config-files  # git仓库地址下的相对地址,可以配置多个,用,分割。
          username:  ***                                            # git仓库的账号
          password:   ****                                           # git仓库的密码
  • 启动类添加注解
@SpringBootApplication
// 声明为 config server 端
@EnableConfigServer
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
  • 测试config server 是否生效

首先我们先要测试server端是否可以读取到github上面的配置信息,直接访问:http://localhost:8778/mengma-config/dev

返回信息如下:

{
    "name": "mengma-config", 
    "profiles": [
        "dev"
    ], 
    "label": null, 
    "version": null, 
    "state": null, 
    "propertySources": [
        {
            "name": "https://github.com/****/config-files/mengma-config-dev.yml", 
            "source": {
                "hello": "mengma.....dev"
            }
        }
    ]
}

上述的返回的信息包含了配置文件的位置、版本、配置文件的名称以及配置文件中的具体内容,说明server端已经成功获取了git仓库的配置信息。

如果直接查看配置文件中的配置信息可访问:http://localhost:8778/mengma-config-dev.yml
返回:

hello: mengma.....dev

修改配置文件mengma-config-dev.yml中配置信息为:hello: mengma.....dev update,再次在浏览器访问http://localhost:8778/mengma-config-dev.yml,返回:

hello: mengma.....dev update、

说明 server 端会自动读取最新提交的内容。

仓库中的配置文件会被转换成web接口,访问可以参照以下的规则:

  • /{application}/{profile}[/{label}]
  • /{application}-{profile}.yml
  • /{label}/{application}-{profile}.yml
  • /{application}-{profile}.properties
  • /{label}/{application}-{profile}.properties

以config-server-dev.yml为例子,它的 applicationconfig-serverprofiledev,client会根据填写的参数来选择读取对应的配置。

label?.....

以config-server-dev.yml为例子,它的application是config-server,profile是dev。client会根据填写的参数来选择读取对应的配置。

client 端

主要展示如何在业务项目中去获取server端的配置信息。

  • 添加依赖
    spring-cloud-starter-config
    spring-boot-starter-web
    spring-boot-starter-test

  • 配置文件

需要配置两个配置文件,application.properties和bootstrap.properties(文件加载优先权)
application.properties如下:

spring.application.name=spring-cloud-config-client
server.port=8002

bootstrap.properties如下:

spring.application.name=config-client
spring.cloud.config.label=master
spring.cloud.config.profile=dev
spring.cloud.config.uri= http://localhost:xxxx/
server.port=8881
  • spring.cloud.config.label 指明远程仓库的分支
  • spring.cloud.config.profile
    dev开发环境配置文件
    test测试环境
    pro正式环境
  • spring.cloud.config.uri= http://localhost:8888/ 指明配置服务中心的网址。

程序的入口类,写一个API接口“/hi”,返回从配置中心读取的 hello 变量的值,代码如下:

@SpringBootApplication
@RestController
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }

    @Value("${hello}")
    String hello;
    @RequestMapping(value = "/hi")
    public String hi(){
        return hello;
    }
}

打开网址访问:http://localhost:8881/hi,网页显示:

mengma.....dev

这就说明,config-client从config-server获取了foo的属性,而config-server是从git仓库读取的,如图:

配置中心服务高可用

客户端都是直接调用配置中心的server端来获取配置文件信息。这样就存在了一个问题,客户端和服务端的耦合性太高,如果server端要做集群,客户端只能通过原始的方式来路由,server端改变IP地址的时候,客户端也需要修改配置,不符合springcloud服务治理的理念。springcloud提供了这样的解决方案,我们只需要将server端当做一个服务注册到eureka中,client端去eureka中去获取配置中心server端的服务既可。

这篇文章我们基于配置中心git版本的内容来改造。

server 端改造

  • 添加依赖

添加 eureka-client 依赖,来添加对eureka 的支持。

  • 配置文件
server:
server:
  port: 8001
spring:
  application:
    name: spring-cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/***/spring-cloud-starter/     # 配置git仓库的地址
          search-paths: config-repo                             # git仓库地址下的相对地址,可以配置多个,用,分割。
          username: username                                        # git仓库的账号
          password: password                                    # git仓库的密码
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8000/eureka/   ## 注册中心eurka地址

增加了eureka注册中心的配置。

这样server端的改造就完成了。先启动eureka注册中心,在启动server端,在浏览器中访问:http://localhost:xxxx/ 就会看到server端已经注册了到注册中心了。

客户端改造

  • 依赖添加
    添加 eureka-client

  • 配置文件

spring:
  cloud:
    config:
      discovery:
        serviceId: spring-cloud-config-server
        enabled: true
      profile: dev
      name: neo-config
      label: master
  application:
    name: spring-cloud-config-client

server:
  port: 8002

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8000/eureka/

主要是去掉了spring.cloud.config.uri直接指向server端地址的配置,增加了最后的三个配置:

spring.cloud.config.discovery.enabled :开启Config服务发现支持
spring.cloud.config.discovery.serviceId :指定server端的name,也就是server端spring.application.name的值
eureka.client.serviceUrl.defaultZone :指向配置中心的地址

这三个配置文件都需要放到bootstrap.yml的配置中。

启动client端,在浏览器中访问:http://localhost:xxxx/ 就会看到server端和client端都已经注册了到注册中心了。

高可用

为了模拟生产集群环境,我们改动server端的端口为8003,再启动一个server端来做服务的负载,提供高可用的server端支持。

如上图就可发现会有两个server端同时提供配置中心的服务,防止某一台挂掉之后影响整个系统的使用。

我们先单独测试服务端,分别访问:http://localhost:8001/neo-config/devhttp://localhost:8003/neo-config/dev返回信息:

再次访问:http://localhost:8002/hello,返回:mengma.....dev update。说明客户端已经读取到了server端的内容,我们随机停掉一台server端的服务,再次访问http://localhost:8002/hello,返回:mengma.....dev update,说明达到了高可用的目的。

推荐阅读更多精彩内容