개발 일기

[Spring Cloud] Spring Cloud Config Server - 2 (Spring Cloud Bus & RabbitMQ) 본문

Back-End/Spring Cloud + MSA + Kubernetes

[Spring Cloud] Spring Cloud Config Server - 2 (Spring Cloud Bus & RabbitMQ)

개발 일기장 주인 2025. 2. 11. 04:49

https://ai-back-end.tistory.com/143

 

[Spring Cloud] Spring Cloud Config Server - 1

기존의 단일 프로젝트 멀티모듈 아키텍처에서는 GitHub Submodule을 사용하여 민감한 정보를 관리하고, 설정 파일이나 시크릿을 별도의 Private Repository로 분리하여 관리했다. 그러나 현재 마이크로서

ai-back-end.tistory.com

 

이전 게시글에서 Spring Cloud Config Server가 뭐하는 놈이고 어떻게 구성되어있으며 어떻게 동작하는지 알아봤다.

그런데 이때 Config Server를 이용하면 설정 정보들이 변경되어도 서버를 다시 빌드하지 않아도 된다는 장점이 있다고 했는데 

 

/actuator/refresh를 통한 설정 정보 갱신

보통은 Spring Boot의 상태를 모니터링 할 수 있는 툴인 Actuator를 Refresh함으로써 정보를 가져올 수 있다.

흔히 쓰는 actuator 의존성을 추가한 후 POST /actuator/refresh를 하게되면

baseurl을 /store로 처리해놔서 /store/refresh

 

그러나 위의 경우 변경이 필요한 모든 Micro Service 들에 대해서 각각 모두 /actuator/refresh를 날려줘야한다.

그렇게 되면 서비스가 한두개면 괜찮은데 수 백개 그 이상 만큼 많다면 POST 요청이 그만큼 필요하게 된다.

 

그렇기 때문에 이때 Spring Cloud Bus라는 것이 도입됐다.


Spring Cloud Bus

Spring Cloud Bus는 분산 시스템에서 구성 변경 및 이벤트를 브로드캐스트할 수 있도록 도와주는 메시지 기반의 시스템입니다.

기존에는 각 마이크로서비스마다 개별적으로 /actuator/refresh 요청을 보내야 했지만, Spring Cloud Bus를 사용하면 한 번의 요청으로 전체 서비스에 변경 사항을 전파

  1. 설정 변경 (Update Config Info)
    : 개발자가 Git 저장소에 있는 설정 파일을 변경 후 push. Git의 설정값이 업데이트됨.
  2. 변경 알림 전송 (Notify Change Via Git Web Hook)
    : Git Webhook이 Config Server의 /actuator/bus-refresh 엔드포인트를 호출.
  3. 메시지 발행 (Publish Message) -> "RefreshRemoteApplicationEvent"
    : Config Server가 Git에서 변경된 설정을 읽고, 메시지 브로커(RabbitMQ, Kafka 등)에 변경 사항을 전파.
    이때, 변경된 설정에 대한 구체적인 정보를 담고 있는 것이 아니라, "설정이 변경되었음을 알리는 이벤트!!"
  4. 설정 변경 알림 (Notify Services)
    : 메시지 브로커가 각 마이크로서비스에 설정 갱신이 필요함을 알림. 변경된 설정을 구독하고 있는 모든 애플리케이션이 메시지를 수신.
    Config Server → 메시지 브로커 (RabbitMQ/Kafka) → 각 클라이언트 서비스 (설정 변경 알림 수신)
  5. 설정 반영 (Reload Config)
    : 각 마이크로서비스가 Config Server에서 최신 설정을 가져와 반영. @RefreshScope가 적용된 Bean이 변경된 설정을 반영함.
    각 클라이언트 서비스는 메시징 시스템을 통해 설정 변경 알림을 수신한 후, 해당 서비스는 Config Server로부터 최신 설정을 가진다.
// 의존성
dependencies {
   implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
}

// RabbitMQ 설치 및 연결
spring:
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    
 // actuator endpoint에 busrefresh 열어놓기
 management:
  endpoints:
    web:
      exposure:
        include: busrefresh
        
// 테스트 용
test:
  message: "Hello from Config Server!"

@RefreshScope

  • @RefreshScope는 Spring Cloud Config와 함께 사용되는 어노테이션으로, 애플리케이션의 설정을 동적으로 갱신할 수 있도록 도와주는 기능을 제공한다.
  • 이 어노테이션을 사용하면, 설정 값이 변경될 때 애플리케이션을 재시작하지 않고도 그 변화를 적용할 수 있다.
  • @RefreshScope가 활성화되면, 해당 빈이 Spring의 컨텍스트에 로드될 때 초기값을 주입받고, Spring Cloud Config의 설정 값이 변경될 때마다 해당 빈이 갱신
  • RefreshScope는 빈의 스코프를 prototype으로 설정하기때문에 해당 빈은 매번 새로운 인스턴스를 생성하여 반환하게 된다.
    따라서 상태를 가지는 빈에는 주의가 필요!!
  • @RefreshScope가 적용된 Bean은 실제 Bean을 감싸는 프록시 객체로 생성ehlsek. 이때 Bean은 캐시(cache)에 저장되고, 이후에 실제 Bean이 호출될 때 캐시된 값이 사용한다. 
    설정값이 변경되면 빈을 Destroy하고 캐시 값도 초기화한다.

 

위 테스트용 같이 config server와 연결해둔 git repo의 store-application-local.yml파일에 설정파일을 올려 두고

테스트용 Config파일과 Controller를 만들어 둔 후 해당 컨트롤러로 curl을 찔러보면

설정 값이 정상적으로 들고 온 것을 알 수 있다.

 

이때 내가 궁금했던 것은 @RefreshScope + (@Value / @ConfigurationProperties)인데 

 

@Value만 (without @RefresScope) 

우선 위와 같이 RefreshScope를 주석처리해두고 /store/busrefresh를 해보겠다.

설정파일의 값을 

test:
message: "Hello from Config Server! - check @RefreshScope"

다음과 같이 수정한 뒤 push했고 

다음과 같이 /actuator/busrefresh (나의 경우 base url 설정을 해둬서 /store/busrefresh임) 해주고 curl로 설정 정보가 업데이트 됐는지 확인해보니 그대로였다.

 

비록 런타임 환경에서 TestConfig 빈이 변경된 설정 값을 바탕으로 새로 재등록되지는 않았지만, RabbitMQ 자체에는 /actuator/bus-refresh 요청이 정상적으로 전달되고 메시지가 브로커에 publish 된 것을 확인할 수 있었다.

즉, @Value의 경우 @RefreshScope를 달아줘야지 런타임 환경에서 빈이 변경된 사항을 바탕으로 빈을 재등록한다.

 

@Value + @RefreshScope

그래서 다시 TestConfig에 @RefreshScope를 달아주고 curl을 찔러보니 서버가 다운타임 없이 빈을 재등록하여 변경된 설정 값을 반환했다.

 

@ConfigurationProperties(prefix = " ") + @RefreshScope

ConfigurationProperties와 RefreshScope를 사용해도 정상적으로 런타임 환경에서 빈이 재등록 됐다.

 

 

@ConfigurationProperties(prefix = " ") (without @RefresScope) 

이 또한 역시 @RefreshScope를 달아놓지 않아서 인지 변경사항이 반영되지 않았다.