SpringCloud系列 (九)Sping Cloud Config分布式配置中心

428 阅读6分钟

Sping Cloud Config分布式配置中心

1、分布式配置中心应用场景

往往,我们使⽤配置⽂件管理⼀些配置信息,⽐如application.yml

单体应⽤架构,配置信息的管理、维护并不会显得特别麻烦,⼿动操作就可以,因为就⼀个⼯程;

微服务架构,因为我们的分布式集群环境中可能有很多个微服务,我们不可能⼀个⼀个去修改配置然后重启⽣效,在⼀定场景下我们还需要在运⾏期间动态调整配置信息,⽐如:根据各个微服务的负载情况,动态调整数据源连接池⼤⼩,我们希望配置内容发⽣变化的时候,微服务可以⾃动更新。

场景总结如下:

(1)集中配置管理,⼀个微服务架构中可能有成百上千个微服务,所以集中配置管理是很重要的(⼀次修改、到处⽣效)

(2)不同环境不同配置,⽐如数据源配置在不同环境(开发dev,测试test,⽣产prod)中是不同的

(3)运⾏期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连接池⼤⼩等配置修改后可⾃动更新

(4)如配置内容发⽣变化,微服务可以⾃动更新配置那么,我们就需要对配置⽂件进⾏集中式管理,这也是分布式配置中⼼的作⽤。

那么,我们就需要对配置⽂件进⾏集中式管理,这也是分布式配置中⼼的作⽤

2、Spring Cloud Config

2.1、Config简介

Spring Cloud Config是⼀个分布式配置管理⽅案,包含了 Server端和 Client端两个部分

  • 我们需要开发一个项目发布服务,这个服务也要注册到注册中心上去,configServer 负责和外部的Git进行交互

  • 微服务A,B,C 直接从Configserver进行交互

Server 端: 提供配置⽂件的存储、以接⼝的形式将配置⽂件的内容提供出去,通过使⽤@EnableConfigServer注解在 Spring boot 应⽤中⾮常简单的嵌⼊

Client 端: 通过接⼝获取配置数据并初始化⾃⼰的应⽤

2.2、Config分布式配置应用

服务端配置

(1) 在github上面,创建一个仓库,名称为lagou-config-repo,并且上传一个配置文件 内容为:

(2)构建Config Server统⼀配置中⼼新建SpringBoot⼯程,引⼊依赖坐标(需要注册⾃⼰到Eureka),名称为 lagou-cloud-configserver-9006

(3)配置pom文件

<dependencies>
  <!--eureka client 客户端依赖引⼊-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

  <!--config配置中⼼服务端-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-config-server</artifactId>
  </dependency>
</dependencies>

(4)新建启动类,加入配置注解 @EnableConfigServer


@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer // 开启配置服务器功能
public class ConfigApp {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApp.class,args);
    }
}

(5)配置application.yml文件

server:
  port: 9006
eureka:
  client:
    serviceUrl: # eureka server的路径
      #把 eureka 集群中的所有 url 都填写了进来,也可以只写⼀台,因为各个 eureka server 可以同步注册表
      defaultZone: http://lagoucloudeurekaservera:8761/eureka/,http://lagoucloudeurekaserverb:8762/eureka/
  instance:
    #使⽤ip注册,否则会使⽤主机名注册了(此处考虑到对⽼版本的兼容,新版本经过实验都是ip)
    prefer-ip-address: true
    #⾃定义实例显示格式,加上版本号,便于多版本管理,注意是ip-address,早期版本是ipAddress
    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@

spring:
  application:
  name: lagou-cloud-config
  cloud:
    config:
      server:
        git:
          uri: https://github.com/langkemaoxin/lagou-config-repo.git
          #配置git服务地址
          username: xxxxx@qq.com #配置git⽤户名
          password: xxxxx #配置git密码
          search-paths:
            - lagou-config-repo
    # 读取分⽀
    label: main

# springboot中暴露健康检查等断点接⼝
management:
  endpoints:
    web:
      exposure:
        include: "*"
  # 暴露健康接⼝的细节
  endpoint:
    health:
      show-details: always

(6)在浏览器地址访问 http://localhost:9006/main/lagou-server-resume-dev.yml 可以直接看到Git的配置信息文件

客户端的配置

下面来改造简历微服务8080

(1)添加配置客户端,依赖

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

(2) 把application.yml改成 bootStrap.yml

bootstrap.yml是系统级别的,优先级⽐application.yml⾼,应⽤启动时会检查这个配置⽂件,在这个配置⽂件中指定配置中⼼的服务地址,会⾃动拉取所有应⽤配置并且启⽤。(主要是把与统⼀配置中⼼连接的配置信息放到bootstrap.yml)

在配置文件,添加配置信息,需要明确指定服务地址URI,服务名称,服务后缀,服务分支

(3)创建一个控制器,用来测试配置,一旦我们使用SpringCloud Config配置后,我们在拿配置信息的时候,就相当于使用本地的配置文件一样

@RestController
@RequestMapping("/config")
public class ConfigController {
    @Value("${lagou.message}")
    private String lagoumessage;
    
    @Value("${mysql.url}")
    private String mysqlUrl;

    @GetMapping("/viewConfig")
    public String viewConfig() {
        String result = "lagouMessage=" + lagoumessage + "   mysqlUrl=" + mysqlUrl;
        return result;
    }
}

(4)访问 http://127.0.0.1:8080/config/viewConfig

3、Config配置手动刷新

在生产中经常会发生修改配置信息的动作,现有的代码,是无法支持动态更新配置文件的,配置文件在一启动的时候,就加入缓存中了,如果想要获取最新的配置信息,只能重启服务了。但是SpringCloud Config 已经提供了一套服务了来做这件事了

解决方案是:使用post请求actuator的refresh接口,刷新缓存

(1)Client客户端添加依赖springboot-starter-actuator(已添加)

(2)Client客户端bootstrap.yml中添加配置(暴露通信端点)

management:
  endpoints:
    web:
      exposure:
        include: "*"

(3)配置类似上面,增加注解@RefreshScope

(4)⼿动向Client客户端发起POST请求,http://localhost:8080/actuator/refresh, 刷新配置信息

(5)进入测试流程,先把仓库的文件进行更新

先把文件改成 db333444

访问配置中心服务,发现配置已经发生了变更

访问简历微服务,发现配置没有变更

使用Post方法,访问8080的Refresh接口 http://localhost:8080/actuator/refresh

再次访问简历微服务的配置接口,发现配置已经更新了

4、Config配置自动更新

实现⼀次通知处处⽣效

拉勾内部做分布式配置,⽤的是zk(存储+通知),zk中数据变更,可以通知各个监听的客户端,客户端收到通知之后可以做出相应的操作(内存级别的数据直接⽣效,对于数据库连接信息、连接池等信息变化更新的,那么会在通知逻辑中进⾏处理,⽐如重新初始化连接池)

在微服务架构中,我们可以结合消息总线(Bus)实现分布式配置的⾃动更新(Spring Cloud Config+Spring Cloud Bus)

4.1、消息总线Bus

所谓消息总线Bus,即我们经常会使⽤MQ消息代理构建⼀个共⽤的Topic,通过这个Topic连接各个微服务实例,MQ⼴播的消息会被所有在注册中⼼的微服务实例监听和消费。换⾔之就是通过⼀个主题连接各个微服务,打通脉络。

4.2 Spring Cloud Config+Spring Cloud Bus 实现⾃动刷新

MQ消息代理,我们还选择使⽤RabbitMQ,ConfigServer和ConfigClient都添加都 消息总线的⽀持以及与RabbitMq的连接信息

(1)ConfigClient客户端, Config Server服务端添加消息总线⽀持

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

(2)ConfigClient客户端, Config Server服务端添加配置

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

(3)暴露端口

建议暴露所有的端⼝
management:
 endpoints:
 web:
 exposure:
 include: "*"

(4)改动Github中的文件,后缀变为777

(5)访问简历微服务-Config客户端,发现后缀还是666

(6)访问配置中心 http://localhost:9006/main/lagou-server-resume-dev.yml 可以发现配置已经更新

(7)调用配置中心的Bus刷新接口,没有返回任何东西

(8)再次访问简历微服务-Config客户端,发现后缀变更成了777

(9)打开RibbitMQ去看,发现有调用的日志记录

并且发现了程序给我们自动生成了一个Topic

4.3、定向更新配置信息

在⼴播模式下实现了⼀次请求,处处更新,如果我只想定向更新呢? 在发起刷新请求的时候http://localhost:9006/actuator/bus-refresh/lagou-service-resume:8081

即为最后⾯跟上要定向刷新的实例的 服务名:端⼝号即可

代码示例