MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Spring Cloud Config 动态配置更新实战

2024-03-281.3k 阅读

一、Spring Cloud Config 简介

在现代微服务架构中,配置管理是一个至关重要的环节。随着微服务数量的增加,管理每个服务的配置变得极为复杂。Spring Cloud Config 为微服务架构中的配置管理提供了一种集中化的解决方案。

Spring Cloud Config 主要由两部分组成:服务器端和客户端。服务器端也称为 Config Server,它是一个可独立运行的微服务应用,用来集中管理应用程序各个环境的配置文件。客户端则是各个微服务,它们从 Config Server 拉取配置信息并应用到自身。

Config Server 支持多种后端存储来存储配置文件,如 Git、SVN 或者本地文件系统等。其中,Git 是最为常用的存储方式,因为它提供了版本控制、易于团队协作等优点。

二、搭建 Spring Cloud Config Server

  1. 创建 Spring Boot 项目 首先,我们使用 Spring Initializr(https://start.spring.io/)来创建一个 Spring Boot 项目。在依赖中添加 “Spring Cloud Config Server”。

  2. 配置项目application.properties 文件中添加如下配置:

server.port=8888
spring.application.name=config-server
spring.cloud.config.server.git.uri=https://github.com/yourusername/yourconfigrepo.git
spring.cloud.config.server.git.search-paths=config-repo
spring.cloud.config.label=master

上述配置中:

  • server.port 指定了 Config Server 的端口为 8888。
  • spring.application.name 设置了应用名称为 config-server
  • spring.cloud.config.server.git.uri 指向了存储配置文件的 Git 仓库地址。
  • spring.cloud.config.server.git.search-paths 表示在 Git 仓库中查找配置文件的路径。
  • spring.cloud.config.label 则指定了使用 Git 仓库的哪个分支,这里是 master 分支。
  1. 启用 Config Server 在主应用类上添加 @EnableConfigServer 注解,启用 Config Server 功能。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

启动项目后,Config Server 就搭建完成了。可以通过 http://localhost:8888/{application}/{profile}[/{label}] 这样的 URL 来访问配置文件。例如,http://localhost:8888/order-service/dev/master 会返回 order-servicedev 环境下的配置信息,这些信息来自 master 分支。

三、Spring Cloud Config Client 接入

  1. 创建 Spring Boot 客户端项目 同样使用 Spring Initializr 创建一个 Spring Boot 项目,并添加 “Spring Cloud Config Client” 依赖。

  2. 配置客户端bootstrap.properties 文件中添加如下配置:

spring.application.name=order-service
spring.cloud.config.uri=http://localhost:8888
spring.cloud.config.profile=dev
spring.cloud.config.label=master

这里:

  • spring.application.name 是客户端应用的名称,要与 Config Server 中存储的配置文件相对应。
  • spring.cloud.config.uri 指向 Config Server 的地址。
  • spring.cloud.config.profile 表示当前客户端所处的环境,如 devprod 等。
  • spring.cloud.config.label 与 Config Server 中的分支对应。
  1. 加载配置 在客户端应用中,可以像使用普通配置文件一样获取从 Config Server 拉取的配置信息。例如,在 application.yml 中定义的配置:
server:
  port: 9000
custom:
  message: Hello from Config Server

在 Java 代码中可以通过 @Value 注解来获取配置值:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class OrderController {
    @Value("${custom.message}")
    private String customMessage;

    @GetMapping("/message")
    public String getMessage() {
        return customMessage;
    }
}

启动客户端应用后,它会从 Config Server 拉取配置信息,并应用到应用中。

四、动态配置更新原理

Spring Cloud Config 的动态配置更新基于 Spring Cloud Bus 和 Spring Boot Actuator。

  1. Spring Cloud Bus Spring Cloud Bus 是一个基于 Spring Boot Actuator 和消息代理(如 RabbitMQ、Kafka 等)的事件总线。它可以在微服务之间传播事件,如配置更新事件。当 Config Server 中的配置文件发生变化时,通过 Spring Cloud Bus 可以将这个变化事件广播到各个微服务客户端。

  2. Spring Boot Actuator Spring Boot Actuator 提供了一系列的端点(endpoint)来监控和管理 Spring Boot 应用。其中,/actuator/refresh 端点用于触发配置的动态更新。当客户端接收到来自 Spring Cloud Bus 的配置更新事件时,会调用 /{application}/actuator/refresh 端点来重新加载配置。

五、实现动态配置更新

  1. 配置 Spring Cloud Bus 在 Config Server 和客户端项目中都添加 Spring Cloud Bus 依赖,例如对于 RabbitMQ:
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

application.properties 中配置 RabbitMQ:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
  1. 启用 Spring Boot Actuator 在客户端项目中,确保 Actuator 相关依赖已添加,并且在 application.properties 中配置:
management.endpoints.web.exposure.include=refresh

这表示暴露 refresh 端点,以便可以通过 HTTP 调用触发配置更新。

  1. 触发动态更新 当 Config Server 中的配置文件发生变化并提交到 Git 仓库后,有两种方式触发客户端的配置更新:
  • 手动触发:通过发送 POST 请求到 /{application}/actuator/refresh 端点。例如,对于 order-service 应用,发送 POST 请求到 http://localhost:9000/actuator/refresh
  • 自动触发:借助 Spring Cloud Bus。当配置文件变化提交到 Git 仓库后,发送 POST 请求到 Config Server 的 /{application}/actuator/bus-refresh 端点。例如,http://localhost:8888/actuator/bus-refresh。Config Server 会通过 Spring Cloud Bus 广播配置更新事件,各个客户端接收到事件后会自动调用 refresh 端点更新配置。

六、配置加密与解密

在实际应用中,配置文件可能包含敏感信息,如数据库密码、API 密钥等。Spring Cloud Config 提供了配置加密与解密功能。

  1. 配置加密 在 Config Server 中配置加密密钥,在 application.properties 中添加:
encrypt.key=yoursecretkey

使用 curl 命令对敏感信息进行加密:

curl localhost:8888/encrypt -d "mypassword"

得到加密后的密文,将其添加到配置文件中,例如:

database.password={cipher}encryptedpasswordhere
  1. 配置解密 客户端应用同样需要配置加密密钥,在 bootstrap.properties 中添加:
encrypt.key=yoursecretkey

当客户端从 Config Server 拉取配置时,会自动对加密的配置值进行解密。

七、高可用配置

为了保证 Config Server 的高可用性,可以部署多个 Config Server 实例,并使用负载均衡器(如 Nginx)进行负载均衡。

  1. 多实例部署 将 Config Server 打包成可执行的 JAR 文件,然后通过不同的端口启动多个实例。例如:
java -jar config-server-1.0.0.jar --server.port=8888
java -jar config-server-1.0.0.jar --server.port=8889
  1. Nginx 配置 在 Nginx 的配置文件中添加如下配置:
upstream config_servers {
    server 192.168.1.100:8888;
    server 192.168.1.100:8889;
}

server {
    listen 80;
    server_name config.example.com;

    location / {
        proxy_pass http://config_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

这样,客户端可以通过 http://config.example.com 来访问 Config Server,Nginx 会将请求负载均衡到不同的 Config Server 实例上。

八、与其他 Spring Cloud 组件集成

  1. 与 Eureka 集成 可以将 Config Server 注册到 Eureka 服务注册中心,使得客户端可以通过 Eureka 来发现 Config Server 的地址。 在 Config Server 项目的 application.properties 中添加 Eureka 相关配置:
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.instance.prefer-ip-address=true

在主应用类上添加 @EnableEurekaClient 注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableConfigServer
@EnableEurekaClient
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

客户端项目同样需要配置 Eureka 相关信息,并在获取 Config Server 地址时使用 Eureka 服务发现:

spring.cloud.config.uri=http://config-server:8888

这里 config-server 是 Config Server 在 Eureka 中的服务名。

  1. 与 Zuul 集成 如果使用 Zuul 作为 API 网关,可以将 Config Server 的请求路由到对应的实例上。在 Zuul 项目的 application.properties 中添加如下配置:
zuul.routes.config-server.path=/config-server/**
zuul.routes.config-server.url=http://config-server:8888

这样,通过 /{application}/{profile}[/{label}] 这样的请求路径,Zuul 会将请求转发到 Config Server。

九、常见问题与解决方法

  1. 配置文件无法加载
  • 原因:可能是 Config Server 地址配置错误、Git 仓库连接问题或者配置文件命名不正确。
  • 解决方法:检查 spring.cloud.config.uri 配置是否正确,确保 Git 仓库地址可访问且配置文件命名符合规则(如 {application}-{profile}.properties)。
  1. 动态更新不生效
  • 原因:可能是 Spring Cloud Bus 配置有误、Actuator 端点未正确暴露或者消息代理连接问题。
  • 解决方法:检查 Spring Cloud Bus 和 RabbitMQ(或其他消息代理)的配置,确保 management.endpoints.web.exposure.include=refresh 配置正确,并且消息代理服务正常运行。
  1. 加密解密失败
  • 原因:可能是加密密钥配置不一致或者加密格式错误。
  • 解决方法:检查 Config Server 和客户端的加密密钥是否一致,确保加密后的配置值格式为 {cipher}encryptedvalue

通过以上详细的步骤和内容,我们深入了解了 Spring Cloud Config 的动态配置更新实战,从搭建 Config Server 和 Client,到实现动态更新、配置加密解密、高可用以及与其他 Spring Cloud 组件的集成,同时也解决了常见的问题。在实际的微服务项目中,合理运用 Spring Cloud Config 可以有效地管理配置,提高项目的可维护性和灵活性。