SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config

一、为什么要统一管理微服务配置

对于传统的单体应用,通常使用配置文件管理所有配置。比如Spring Boot开发的单体应用,配置内容可以放在application.yml文件,需要切换环境的话可以设置多个Profile并在启动应用时指定spring.pfofiles.active={profile}。

然而,在微服务架构中,配置管理一般有以下需求

  • 集中管理配置:一个使用微服务架构的应用系统可能会包含成千上万个微服务,因此集中管理配置是非常有必要的。
  • 不同环境不同配置:例如,数据源配置在不同的环境(开发、测试、预发布、生产等)中是不同的。
  • 运行期间可动态调整:例如,可根据各个微服务的负载情况,动态调整数据源连接池大小或熔断阈值,并且在调整配置时不停止微服务。
  • 配置修改后可自动更新。如配置内容发生变化,微服务能够自动更新配置。

所以,对于微服务架构而言,一个通用的配置管理机制是必不可少的,常见做法是使用配置服务器管理配置。 

二、Spring Cloud Config简介

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

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

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

Spring Cloud Config的架构图如下

SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config_第1张图片

所有微服务都指向Config Server。各个微服务在启动时,会请求Config Server以获取所需要的配置属性,然后缓存这些属性以提高性能。 

三、编写Config Server

1)在码云仓库https://gitee.com/thunderclap/spring-cloud-config-repo中新建一个文件夹order,在里面新建几个配置文件。

通常,配置文件的名称格式为“服务名称-环境.properties”(或者“服务名称-环境.yml”),其中环境常用的有以下几种

  • dev:开发
  • prd:生产
  • pre:预发布
  • sit:测试

例如


config-client-dev.properties

config-client-prd.properties

config-client-pre.properties

config-client-sit.properties


其中config-client为服务名称。 

内容分别是


prifile=dev-1.0

prifile=prd-1.0

prifile=pre-1.0

prifile=sit-1.0


效果如下 

SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config_第2张图片

2)创建一个maven工程microservice-config-server,pom.xml文件添加如下依赖



    4.0.0

    cn.zhh
    microservice-config-server
    1.0
    
    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.1.RELEASE
    

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Finchley.M7
                pom
                import
            
        
    
    
    
        
        
            org.springframework.cloud
            spring-cloud-config-server
        
		
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
    

    
    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/libs-milestone
            
                false
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

为了利用服务发现组件的优势,需要将该服务注册到Eureka Server上。

3)编写配置文件application.yml,并在其中添加如下内容

server:
  port: 8085
spring:
  application:
    # 服务名称,客户端需要使用此名称查询配置中心服务端
    name: config-server
  cloud:
    config:
      server:
        git:
          # 配置码云仓库地址
          uri: https://gitee.com/thunderclap/spring-cloud-config-repo.git
          # 搜索路径(文件夹,可以多个)
          search-paths:
          - order
      # 分支
      label: master
# eureka server
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8080/eureka/

因为是测试,所以没有设置用户名密码。

4)在启动类上添加注解@EnableConfigServer,声明这是一个Config Server,同时也要加上@EnableDiscoveryClient,将服务注册到Eureka Server。

@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class MicroserviceConfigServerApplication {

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

}

这样,一个Config Server就完成了。

下面讲一下Config Server的端点

可以使用Config Server的端点获取配置文件的内容。端点与配置文件的映射规则如下


/{application}/{profile}/[{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties


以上端点都可以映射到{application}-{profile}.properties这个配置文件,{application}表示微服务的名称,{label}表示仓库分支,默认是master,{profile}表示环境。

启动服务,访问http://localhost:8085/config-client/dev得到如下结果

SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config_第3张图片

可以直观地看到应用名称、项目profile、仓库分支、仓库版本、配置文件URL、配置详情等信息。

访问http://localhost:8085/config-client-dev.properties,返回配置文件中的属性

四、编写Config Client

1)创建一个maven工程microservice-config-client,pom.xml文件添加如下依赖



    4.0.0

    cn.zhh
    microservice-config-client
    1.0
    
    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.1.RELEASE
    

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Finchley.M7
                pom
                import
            
        
    
    
    
    	
        
        	org.springframework.boot
        	spring-boot-starter-web
        
        
        
            org.springframework.cloud
            spring-cloud-starter-config
        
		
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
    

    
    
        
            spring-milestones
            Spring Milestones
            https://repo.spring.io/libs-milestone
            
                false
            
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

2)编写配置文件application.yml,并在其中添加如下内容

server:
  port: 8086

3)编写配置文件bootstrap.yml,并在其中添加如下内容

spring:
  application:
    name: config-client
  cloud:
    config:
      # 环境
      profile: pre
      # 分支
      label: master
      discovery:
        enabled: true
        service-id: config-server
# eureka server
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8080/eureka/

Config Client必须在bootstrap.yml或bootstrap.properties中配置。

原因:Spring Cloud有一个“引导上下文”的概念,这是主应用程序的父上下文,负责从配置服务器加载配置属性,以及解密外部配置文件中的属性。引导上下文加载bootstrap.*中的属性,比主应用程序加载application.*中的属性有更高的优先级,并且默认情况下不能被本地配置覆盖。

4)在启动类上添加@EnableDiscoveryClient,将服务注册到Eureka Server。

@SpringBootApplication
@EnableDiscoveryClient
public class MicroserviceConfigClientApplication {

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

}

5)添加一个读取配置的Controller类用来测试。

@RestController
public class ConfigClientController {

	@Value("${profile}")
	private String profile;
	
	@GetMapping("profile")
	public String getProfile() {
		return profile;
	}
}

6)先启动Eureka Server和Config Server,然后启动该应用。访问http://localhost:8086/profile,返回以下结果

说明获得了仓库中配置文件的信息。 

五、Config Server的仓库配置详解

1、占位符支持

Config Server的占位符支持{application}、{profile}和{label}。

如spring.cloud.config.server.git.uri:https://gitee.com/thunderclap/{application}.git。

2、模式匹配

模式匹配指的是带有通配符的{application}/{profile}名称的列表。

3、搜索目录

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/thunderclap/spring-cloud-config-repo.git
          # 搜索路径(文件夹,可以多个),支持占位符如bar*
          search-paths:
          - order

4、启动时加载配置文件

spring:
  cloud:
    config:
      server:
        git:
          # 配置码云仓库地址
          uri: https://gitee.com/thunderclap/spring-cloud-config-repo.git
          clone-on-start: true

以上是全局配置,可以单个仓库独自配置的。 

六、Config Server的健康状况指示器

// TODO

七、配置内容的加解密

// TODO

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

很多场景下,如果配置发生了修改,需要微服务在运行期间动态刷新调整。

怎么做呢?利用spring-boot-starter-actuator的/refresh端点可以做到,其原理是重新将bean注册到IOC容器。

1)pom.xml文件引入actuator的依赖。

        
        	org.springframework.boot
        	spring-boot-starter-actuator
        

2)application.yml配置文件开启所有服务端点权限。

management:
  endpoints:
    web:
      exposure:
        # 开启所有服务端点权限
        include: "*"

3)注入配置属性的类上面增加注解@RefreshScope。

@RestController
@RefreshScope
public class ConfigClientController {

	@Value("${profile}")
	private String profile;
	
	@GetMapping("profile")
	public String getProfile() {
		return profile;
	}
}

4)修改仓库上的配置属性,post请求方式调用http://localhost:8086/actuator/refresh接口。

SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config_第4张图片

5)重新访问http://localhost:8086/profile,可以看到配置的值发生了改变。

九、使用Spring Cloud Bus自动刷新配置

使用/refresh端点手动刷新配置,只能刷新单个JVM的,每个微服务都这么去搞,工作量很大。随着系统的不断扩张,越来越难维护。这时候,实现配置的自动刷新就很有必要了。Spring Cloud Bus可以做到这些。

1、Spring Cloud Bus简介

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

SpringCloud2.x(七)统一管理微服务配置——Spring Cloud Config_第5张图片

由图可知,微服务A的所有实例都通过消息总线连接到了一起,每个实例都会订阅配置更新事件。当其中一个微服务节点的/bus/refresh端点被请求时,该实例就会向消息总线发送一个配置更新时间,其它实例获得该事件后也会更新配置。

2、实现自动刷新

安装RabbitMQ,参考教程https://www.cnblogs.com/ericli-ericli/p/5902270.html。

1)pom.xml文件添加以下依赖

        
        	org.springframework.cloud
        	spring-cloud-starter-bus-amqp
        

2)bootstrap.yml配置文件中添加以下内容

spring
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

3)启动项目,然后修改端口再启动一次。修改仓库文件内容后,发送POST请求到其中一个Config Client实例的/bus/refresh端点,然后访问两个Config Client节点的/profile端点,会发现两个节点都会返回修改后的值,说明配置内容已被刷新。

如果使用Git仓库,可以借助WebHooks监听文件变化自动发送请求,轻松实现配置的自动更新。

3、局部刷新

某些场景下(例如灰度发布等),若只想刷新部分微服务的配置,可通过/bus/refresh端点的destination参数来定位要刷新的应用程序。

例如:/bus/refresh?destination=consumers:9000,这样消息总线上的微服务实例就会根据destination参数的值来判断是否需要刷新。其中,consumers:9000指的是各个微服务的ApplicationContextID。

destination参数也可以用来定位特定的微服务。例如:/bus/refresh?destination=consumers:**,这样就可以触发customers微服务所有实例的配置刷新。

配置的局部刷新与ApplicationContextID有关。默认情况下,ApplicationContextID是spring.application.name:server.port。

4、架构改进

通过请求某个微服务/bus/refresh端点来实现配置刷新的方式并不优雅。原因如下

破坏了微服务的职责是单一原则。业务微服务只应关心自身业务,不应承担配置刷新的职责。

破坏了微服务各节点的对等性。

有一定的局限性。例如,微服务在迁移时,网络地址经常会发生变化。此时如果想自动刷新配置,就要修改WebHook的配置。

如果将Config Server也加入到消息总线中,并使用Config Server的/bus/refresh端点来实现配置的刷新。这样,各个微服务只需要关心自身的业务,而不再承担配置刷新的职责。

5、跟踪总线事件

一些场景下如果希望知道Spring Cloud Bus事件传播的细节,可以跟踪总线事件(RemoteApplicationEvent的子类都是总线事件)。

只需设置spring.cloud.bus.trace.enabled=true,就可以在/bus/refresh端点被请求后,访问/trace端点获得事件的传播细节了。

十、Spring Cloud Config的用户认证

在Config Server添加以下依赖

        
            org.springframework.boot
            spring-boot-starter-security
        

在application.yml添加以下配置

security:
    basic:
        enabled: true    # 开启基于HTTP basic的认证
    # 如果不设置,账号默认是user,密码是一个随机值,该值会在启动时打印出来
    user:
        name: user    # 配置登录的账号是user
        password: 123456    # 配置登录的密码是123456

Config Client连接需要认证的Config Server

方式一:使用curl风格的URL,例如

spring:
    cloud:
        config:
            url: http://user:123456@localhost:8080/

方式二:指定Config Server的账号与密码,例如

spring:
    cloud:
        config:
            url: http://localhost:8080/
            username: user
            password: 123456

方式二的优先级比方式一高。

十一、Config Server的高可用

1、Git仓库的高可用

1)使用第三方Git仓库。比如使用GitHub、BitBucket、get@osc、Coding等提供的仓库托管服务。

2)自建Git仓库管理系统。

2、Rabbit MQ的高可用

使用消息总线实现自动刷新时用到的消息中间件也需要保证高可用。

3、Config Server自身的高可用

1)借助一个负载均衡器来实现:各个微服务将请求发送到负载均衡器(比如Nginx),负载均衡器将请求转发到其代理的其中一个Config Server节点。

2)Config Server注册到Eureka Server上:将多个配置服务节点注册到Eureka。

 

你可能感兴趣的:(Spring,Cloud,2.x)