天天看点

Spring Cloud 之Config分布式集中配置中心详解

1.为什么需要配置中心?

1、集中管理配置  2、不同环境不同配置  3、运行期间动态调整配置   4、自动刷新
           

Spring Cloud Config为分布式系统外部化配置提供了服务器端和客户端的支持,它包括 Config Server和Config Client两部分。

Config Server是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环 境下的配置,默认使用Git存储配置内容(也可使用Subversion、本地文件系统或Vault存储 配置),因此可以方便的实现对配置的版本控制与内容审计。

Config Client 是Config Server的客户端,用于操作存储在Config Server中的配置属性

2.服务端配置,Config Server

pom.xml

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
           

启动类上添加@EnableConfigServer注解,表示这个类是一个Config Server

@SpringBootApplication
@EnableConfigServer
public class SpringConfigServerApplication {

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

配置application.yml文件

server:
 port: 
spring:
 cloud:
  config:
   server:
    git:
     uri: https://github.com/songxiansen521/spring-cloud-config-repo.git
     username: ****your git name****
     password: ****your git pw****
           
/{label}/{application}-{profile}.yml
/{label}/{application}-{profile}.properties
以上端点都可以映射到{application}-{profile}.properties这个配置文件,
{application}表 示微服务的名称,{label}对应Git仓库的分支,默认是 master
           

3. 编写Config Client

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
           

编写配置文件application.yml

bootstrap.yml的配置文件,配置在bootstrap.xml中的属性有更高的优先级,默认情况下不会被本地覆盖,spring cloud有一个“引导上下文”的概念,这是主应用程序的父上下文。引导上下文负责 从配置服务器加载配置属性,以及解密外部配置文件中的属性。和主应用程序加载 application.(yml或 properties)中的属性不同,引导上下文加载(bootstrap.)中的属性。 配置在 bootstrap.*中的属性有更高的优先级,因此默认情况下它们不能被本地配置覆盖

spring:
 application:
  #对应config server中配置文件的{application}
  name: microservice-foo
 cloud:
  config:
    #访问config server的地址
    uri: http://localhost:8001
    #对应config server中配置文件的{profile}
    profile: dev
    #对应config server中配置文件的{label}
    label: master
           

添加Controller类

@RestController
public class ConfigClientController {

    @Value("${profile}")
    private String profile;

    @GetMapping("/getProfile")
    public String hello(){
        return this.profile;
    }
}
           

使用/refresh端点手动刷新配置

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
           

在controller上添加@RefereshScope,该注解会在配置更改时得到特殊的处理。

@RestController
@RefreshScope
public class ConfigClientController {

    @Value("${profile}")
    private String profile;

    @GetMapping("/getProfile")
    public String hello(){
        return this.profile;
    }
}
           

启动项目,http://localhost:8002/getProfile 访问修改Git仓库中配置文件内容,再次访问,发现结果没变化。

这时,就需要手动刷新:以POST请求,访问http://localhost:8001/refresh

Spring Cloud Bus就可以实现配置的自动刷新

Spring Cloud Bus使用轻量级的消息代理(例如 RabbitMQ、 Kafka等)连接分布式系统 的节点,这样就可以广播传播状态的更改(例如配置的更新)或者其他的管理指令。可将 Spring Cloud Bus想象成一个分布式的Spring Boot Actuator。

1、提交代码触发post给客户端A发送bus/refresh

2、客户端A接收到请求从Server端更新配置并且发送给Spring Cloud Bus

3、Spring Cloud bus接到消息并通知给其它客户端

4、其它客户端接收到通知,请求Server端获取最新配置

5、全部客户端均获取到最新的配置

1、提交代码触发post请求给bus/refresh

2、server端接收到请求并发送给Spring Cloud Bus

3、Spring Cloud bus接到消息并通知给其它客户端

4、其它客户端接收到通知,请求Server端获取最新配置

5、全部客户端均获取到最新的配置

使用RabbitMQ来做示例

需要多引入spring-cloud-starter-bus-amqp包,增加对消息总线的支持

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
           

配置文件

## 刷新时,关闭安全验证
management.security.enabled=false
## 开启消息跟踪
spring.cloud.bus.trace.enabled=true

spring.rabbitmq.host=
spring.rabbitmq.port=
spring.rabbitmq.username=admin
spring.rabbitmq.password=
           

server端配置

server:
  port: 
spring:
  application:
    name: spring-cloud-config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/ityouknow/spring-cloud-starter/  
                                           # 配置git仓库的地址
          search-paths: config-repo       # git仓库地址下的相对地址,
                                            可以配置多个,用,分割。
          username: username # git仓库的账号
          password: password   # git仓库的密码
  rabbitmq:
    host: 
    port: 
    username: admin
    password: 

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8000/eureka/  ## 注册中心eurka地址


management:
  security:
     enabled: false
           

Spring Config Server与Eurelka配合使用

Config Client配置

spring:
 application:
  #对应config server中配置文件的{application}
  name: microservice-foo
 cloud:
  config:
    #访问config server的地址
    #uri: http://localhost:8001
    #对应config server中配置文件的{profile}
    profile: dev
    #对应config server中配置文件的{label}
    label: master
    discovery:
      #表示使用服务发现组件中提供的Config Server,默认是false
      #开启通过服务发现组件访问Config Server的功能
      enabled: true
      #指定Config Server在服务发现组件中的serviceId 默认是configserver
      service-id: microservice-config-server-eureka
eureka:
 client:
  service-url:
   defaultZone: http://localhost:8888/eureka/
           

Config Server服务端

server:
 port: 
spring:
 appliation:
  name: microservice-config-server-eureka
 cloud:
  config:
   server:
    git:
     uri: https://github.com/songxiansen521/spring-cloud-config-repo.git
     username: ***your git name***
     password: ***your git pw***
eureka:
 client:
  service-url:
   defaultZone: http://localhost:8888/eureka/
           

配置信息的加解密安全处理

前文是在 Git仓库中明文存储配置属性的。很多场景下,对于某些敏感的配置内容(例如数 据库账号、密码等),应当加密存储。 config server为配置内容的加密与解密提供了支 持

安装JCE

config server的加解密功能依赖Java Cryptography Extension(JCE) Java8 JCE下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download2133166.html 下载JCE并解压,将其中的jar包覆盖到JDK/jre/lib/security目录中

增加一个配置文件bootstrap.yml,配置对称加密的密钥

实际应用中会涉及很多敏感的数据,这些数据会被加密保存到 SVN 仓库中,最常见的就是数据库密码。Spring Cloud Config 为这类敏感数据提供了加密和解密的功能,加密后的密文在传输给客户端前会进行解密。配置服务支持对称加密(AES算法)和非对称加密(RSA算法)。

在使用配置服务的加密和解密功能,首先必须安装 JCE(Java Cryptography Extension),可以到 Oracle 的官方网站下载(下载地址),解压缩后会得到 local_policy.jar 和 US_export_policy.jar 两个 jar 包,将其复制到 $JAVA_HOME/jre/lib/security 目录中,即可完成安装。

encrypt:
    key:tuling #设置对称秘钥
           

http://localhost:8080/encrypt 加密

http://localhost:8080/decrypt 解密

服务端配置中心是密文,客户端是明文

spring:
    application:
        name:spring-cloud-config-client-dev
server:
    port:
info:
    name:refresh
    desc:aa
mysql:
    passwd:'{cipher}b60b034ba08e4f4d02135a5a1eb3167
9506667afe91e0da7245fafdd9b0a1d19'
           

BUG

/bus/refresh 有一个很严重的BUG,一直没有解决:对客户端执行/bus/refresh之后,挂到总线的上的客户端都会从Eureka注册中心撤销登记;如果对server端执行/bus/refresh,server端也会从Eureka注册中心撤销登记。再用白话解释一下,就是本来人家在Eureka注册中心注册的好好的,只要你对着它执行一次/bus/refresh,立刻就会从Euraka中挂掉。

其实这个问题挺严重的,本来你利用/bus/refresh给所有的节点来更新配置信息呢,结果把服务从Euraka中给搞掉了,那么如果别人需要调用客户端的服务的时候就直接歇菜了。不知道国内有童鞋公司在生产中用到这个功能没有,用了不就很惨烈。在网上搜索了一下,国内网友和国外网友都遇到过很多次,但是一直没有解决,很幸运就是我在写这篇文章的前几天,Netflix修复了这个问题,使用Spring Cloud最新版本的包就可以解决这个问题。由此也可以发现Spring Cloud还在快速的发展中,最新的版本可能也会有一些不稳定性,可见路漫漫而修远兮。

在pom中使用Spring Cloud的版本,解决这个bug.D版本,Dalston

<properties>
    <project.build.sourceEncoding>UTF-</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-</project.reporting.outputEncoding>
    <java.version></java.version>
    <spring-cloud.version>Dalston.SR1</spring-cloud.version>
</properties>
           

Config Server的高可用

nigix 借助负载均衡实现

Config Server的高可用也可借助Eureka实现。

继续阅读