Giới thiệu về Config Server
Khi số lượng microservice tăng lên, việc quản lý cấu hình trở nên phức tạp và tốn kém về mặt vận hành. Giải pháp là xây dựng một trung tâm cấu hình để quản lý tập trung các thiết lập.
Trung tâm cấu hình gồm hai thành phần: phía server lấy cấu hình từ Git repository (như GitHub), còn phía client là các service đã đăng ký với Eureka, sẽ kéo cấu hình từ server về. Tài liệu tham khảo chính thức có tại: https://docs.spring.io/spring-cloud-config/docs/current/reference/html/.
Xây dựng service Config Server (port 3344)
Bắt đầu bằng khai báo dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Cấu hình ứng dụng trong file YAML:
server:
port: 3344
spring:
application:
name: config-center-service
cloud:
config:
server:
git:
uri: https://gitee.com/****/springcloud-config
label: master
eureka:
instance:
hostname: config-server-host
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
Lớp khởi chạy chính cần kích hoạt cả Eureka Client và Config Server:
@EnableEurekaClient
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Tạo file cấu hình mẫu trên Gitee:
config:
info: "Phiên bản 1 từ nhánh master"
Truy cập cấu hình qua URL: http://localhost:3344/master/config-dev.yaml. Định dạng chuẩn là: /{label}/{application}-{profile}.yml.
Tạo ứng dụng client tiêu thụ cấu hình (port 3355)
Sử dụng file bootstrap.yml thay vì application.yml do mức độ ưu tiên cao hơn:
server:
port: 3355
spring:
application:
name: config-client-app
cloud:
config:
label: master
name: config
profile: dev
uri: http://127.0.0.1:3344
eureka:
client:
service-url:
defaultZone: http://eureka7001.com:7001/eureka
fetch-registry: true
register-with-eureka: true
Lớp khởi chạy:
@EnableEurekaClient
@SpringBootApplication
public class ConfigClientApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigClientApplication.class, args);
}
}
Controller đọc giá trị cấu hình:
@Slf4j
@RefreshScope
@RestController
public class ConfigurationController {
@Value("${config.info}")
private String configurationData;
@GetMapping("/configuration/data")
public String getConfiguration() {
return configurationData;
}
}
Cập nhật cấu hình động
Khi cấu hình trên Git được thay đổi, chỉ server nhận được cập nhật mới, client vẫn giữ giá trị cũ cho đến khi restart. Để khắc phục, cần thêm thư viện Actuator:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Mở endpoint refresh trong cấu hình:
management:
endpoints:
web:
exposure:
include: info,health,beans,env,refresh
Gửi yêu cầu cập nhật cấu hình:
curl -X POST "http://localhost:3355/actuator/refresh"
Spring Cloud Bus - Giải pháp cập nhật hàng loạt
Vấn đề phát sinh khi phải gọi refresh từng service thủ công. Spring Cloud Bus giải quyết điều này thông qua message broker như RabbitMQ. Nguyên lý hoạt động: khi một service nhận thông báo cập nhật, nó sẽ gửi sự kiện vào topic chung, các service khác lắng nghe cùng topic sẽ tự động cập nhật cấu hình.
Tài liệu chính thức: https://docs.spring.io/spring-cloud-bus/docs/current/reference/html/.
Cài đặt RabbitMQ
- Cài đặt Erlang từ https://www.erlang.org/downloads.
- Tải RabbitMQ tại https://github.com/rabbitmq/rabbitmq-server/releases.
- Chạy lệnh sau trong thư mục sbin để bật plugin quản lý:
rabbitmq-plugins.bat enable rabbitmq_management. - Khởi động service qua Task Manager.
- Truy cập giao diện quản lý tại http://localhost:15672/, tài khoản mặc định: guest/guest.
Hai mô hình triển khai Bus
- Gọi endpoint /bus/refresh từ một client bất kỳ → tất cả client cập nhật.
- Gọi endpoint /bus/refresh từ Config Server → tất cả client cập nhật.
Nên sử dụng cách thứ hai vì không làm mất đi tính đồng đẳng giữa các service và tuân thủ nguyên tắc trách nhiệm duy nhất.
Tích hợp Bus vào client mới (port 3366)
Thêm dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Cấu hình kết nối RabbitMQ:
server:
port: 3366
spring:
application:
name: bus-enabled-client
cloud:
config:
label: master
name: config
profile: dev
uri: http://127.0.0.1:3344
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka
management:
endpoints:
web:
exposure:
include: refresh
Cập nhật Config Server:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
Cấu hình mở endpoint busrefresh:
management:
endpoints:
web:
exposure:
include: busrefresh
Lệnh cập nhật toàn bộ services:
curl -X POST "http://localhost:3344/actuator/busrefresh"
Lệnh cập nhật service cụ thể:
curl -X POST "http://localhost:3344/actuator/busrefresh/bus-enabled-client:3366"
Khi client khởi động, nó sẽ tự động tạo topic springCloudBus trong RabbitMQ để lắng nghe sự kiện.