Experience/LG CNS AM Inspire Camp 1기

[LG CNS AM Inspire Camp] 22. Spring Cloud Bus와 RabbitMQ로 설정 변경 실시간 전파하기

chillmyh 2025. 5. 14. 01:39

이미지 출처 : https://velog.io/@jjh5887/Spring-Cloud-Bus-with-RabbitMQ

1. 들어가며

 Spring Cloud Config로 설정을 중앙화했지만, 변경사항을 각 서비스에 적용하는 과정이 여전히 번거롭다면 Spring Cloud Bus가 해결책이 될 수 있다. 이 글에서는 Spring Cloud Bus와 RabbitMQ를 활용하여 마이크로서비스 환경에서 설정 변경을 자동으로 전파하는 방법을 정리해본다.

 

2. 왜 Spring Cloud Bus가 필요한가?

마이크로서비스 아키텍처에서는 여러 서비스 인스턴스가 동시에 실행되는 경우가 많다. 이런 환경에서 설정을 변경하려면 다음과 같은 문제에 직면하게 된다.

2.1 Spring Cloud Config의 한계

Spring Cloud Config는 설정을 중앙화하는 훌륭한 도구이지만, 다음과 같은 한계가 있다.

  • Spring Cloud Config는 설정 파일을 중앙 저장소(Git, SVN 등)에서 제공하는 역할만 담당
  • 설정 변경 후 이를 각 서비스에 자동으로 반영하지는 못함
  • 설정 변경사항을 적용하려면 각 서비스마다 /actuator/refresh 엔드포인트를 수동으로 호출해야 함
  • 또는, 설정 변경사항을 적용하기 위해 서비스 재배포를 해야함
# 서비스마다 이 명령을 실행해야 함
curl -X POST http://service-1:8080/actuator/refresh
curl -X POST http://service-2:8080/actuator/refresh
curl -X POST http://service-3:8080/actuator/refresh
# ... 수십, 수백 개의 서비스 인스턴스가 있다면?

 

이는 서비스 인스턴스가 많을수록 운영 부담이 커지는 문제를 야기시킨다.

 

2.2 설정 변경의 자동화 필요성

여러 서비스 인스턴스에 설정 변경을 전파하기 위해서는 다음과 같은 기능이 필요하다

  • 하나의 명령으로 모든 서비스에 변경 사항 전파
  • 신규 배포된 서비스 인스턴스도 자동으로 최신 설정 적용
  • 특정 서비스 타입이나 그룹에만 설정 변경 전파 가능

이러한 요구사항을 충족하기 위해 Spring Cloud Bus가 등장했다.

 

3. Spring Cloud Bus의 동작 원리

3.1 구성 요소와 흐름

Spring Cloud Bus는 분산 시스템의 노드를 경량 메시지 브로커로 연결한다. 핵심 구성 요소와 동작 흐름은 다음과 같다.

  • 메시지 브로커: RabbitMQ나 Kafka와 같은 메시지 브로커를 통해 이벤트 전파
  • 이벤트 흐름: 특정 서비스 인스턴스에서 /actuator/busrefresh 엔드포인트 호출 → 메시지 브로커를 통해 모든 연결된 서비스로 이벤트 전파 → 각 서비스는 이벤트를 받아 설정 갱신
  • 느슨한 일관성: 실시간 업데이트가 아닌 이벤트 기반 비동기 전파 방식
  • 단방향 푸시: 서비스가 주기적으로 변경사항을 확인하는 폴링(polling) 방식이 아닌 이벤트 푸시 방식

3.2 RabbitMQ가 하는 역할

RabbitMQ는 Spring Cloud Bus의 메시지 브로커로서 다음과 같은 역할을 수행한다.

  • 이벤트 브로커: 큐 기반 메시지 전달 시스템으로 서비스 간 이벤트 라우팅
  • 메시지 보장: 서비스 장애 시에도 메시지 유실 방지
  • 유연한 라우팅: 설정에 따라 특정 서비스 그룹에만 메시지 전달 가능
  • 다양한 이벤트 지원: 설정 변경뿐만 아니라 사용자 정의 이벤트도 전파 가능

RabbitMQ 외에도 Kafka를 사용할 수 있지만, RabbitMQ가 설정이 더 간단하고 가벼워서 Spring Cloud Config에 더 많이 사용된다.

 

4. Spring Cloud Bus + RabbitMQ 연동 실습

4.1 RabbitMQ 설치

간단한 방법으로는 Docker를 사용하여 RabbitMQ를 실행한다.

docker run -d --hostname rabbit --name rabbitmq \
  -p 5672:5672 -p 15672:15672 \
  rabbitmq:3-management

 

설치 후 http://localhost:15672에서 관리 콘솔에 접속할 수 있다(기본 계정: guest/guest).

 

4.2 Config Server에 Spring Cloud Bus 추가

Config Server에 Spring Cloud Bus를 추가하기 위해 다음과 같이 의존성을 추가한다.

dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
}

 

application.yml 또는 application.properties에 RabbitMQ 연결 정보를 설정한다.

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
  cloud:
    bus:
      enabled: true

 

4.3 Config Client에 Spring Cloud Bus 추가

각 서비스(Config Client)에도 동일한 의존성과 설정을 추가해야 한다.

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
}

 

그리고 Actuator 엔드포인트를 활성화한다.

management:
  endpoints:
    web:
      exposure:
        include: bus-refresh, refresh, info, health

 

4.4 설정 변경 테스트

이제 설정 변경 시 모든 서비스에 자동으로 전파되는지 테스트해보자.

  1. Git 저장소에서 설정 파일을 수정하고 커밋한다.
  2. 아무 서비스 인스턴스에서 다음 명령을 실행한다.
curl -X POST http://localhost:8080/actuator/busrefresh

  3. 모든 서비스 인스턴스에서 로그를 확인하면 설정이 갱신되는 것을 볼 수 있다.

INFO 12345 --- [nio-8080-exec-1] o.s.c.c.monitor.RefreshEventListener    : Received remote refresh request
INFO 12345 --- [nio-8080-exec-1] o.s.boot.context.config.ConfigDataLoader : Loaded config data from 'configserver:'
INFO 12345 --- [nio-8080-exec-1] o.s.cloud.context.scope.GenericScope    : BeanFactory id=xxx refreshed

 

5. 커스텀 이벤트 전파도 가능

Spring Cloud Bus는 설정 갱신 외에도 사용자 정의 이벤트를 전파할 수 있다.

5.1 RemoteApplicationEvent 확장

사용자 정의 이벤트를 만들기 위해 RemoteApplicationEvent 를 상속 받는다.

public class CustomEvent extends RemoteApplicationEvent {
    private String message;
    
    // 기본 생성자 (직렬화에 필요)
    public CustomEvent() {
    }
    
    // 이벤트 생성 시 사용할 생성자
    public CustomEvent(Object source, String originService, String message) {
        super(source, originService);
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
}

 

5.2 이벤트 발송 및 수신

이벤트를 보내는 방법

@Autowired
private ApplicationEventPublisher publisher;

public void sendCustomEvent(String message) {
    publisher.publishEvent(new CustomEvent(this, 
        "${spring.application.name}:${server.port}", message));
}

 

이벤트를 수신하는 방법

@EventListener
public void handleCustomEvent(CustomEvent event) {
    log.info("Received custom event: {}", event.getMessage());
    // 이벤트에 따른 처리 로직
}

 

5.3 이벤트 클래스 등록

사용자 정의 이벤트를 사용하려면 애플리케이션에 등록해야 한다.

@SpringBootApplication
@EnableBinding(SpringCloudBusClient.class)
@RemoteApplicationEventScan(basePackages = "com.example.events")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

이렇게 하면 비지니스 이벤트도 Spring Cloud Bus를 통해 모든 서비스에 전파할 수 있다.

 

6. 주의사항

6.1 안정성과 장애 대응

 

  • RabbitMQ 이중화: 프로덕션 환경에서는 RabbitMQ 클러스터를 구성하여 단일 장애점을 제거
  • 메시지 전달 보장: RabbitMQ가 중단되면 이벤트 전파가 실패하므로, 중요한 설정은 이벤트 전달 여부를 모니터링
  • 서킷 브레이커 패턴: RabbitMQ 연결 실패 시 대체 메커니즘(폴링 또는 수동 갱신)으로 전환

6.2 보안 고려사항

 

  • actuator 엔드포인트 보안: /actuator/busrefresh는 강력한 엔드포인트이므로 인증을 통해 보호
  • 메시지 암호화: 민감한 설정 정보는 전송 중에 암호화
management:
  endpoints:
    web:
      exposure:
        include: bus-refresh
  endpoint:
    busrefresh:
      enabled: true
  security:
    enabled: true

 

 

 

6.3 설정 변경 범위 제한

특정 서비스 그룹에만 설정 변경을 적용하고 싶다면 대상을 지정할 수 있다.

# users 서비스만 갱신
curl -X POST http://localhost:8080/actuator/busrefresh/users:**

 

6.4 성능 고려사항

 

  • 불필요한 리프레시 최소화: 설정 변경이 잦으면 서비스 성능에 영향을 줄 수 있음
  • 대규모 시스템에서의 확장성: 서비스가 수백 개인 경우 Kafka가 더 적합할 수 있음
  • 서비스 재시작이 필요한 설정: 일부 설정은 런타임에 갱신할 수 없으므로 문서화 필요

7. 마무리

Spring Cloud Bus와 RabbitMQ를 활용하면 마이크로서비스 환경에서 설정 변경을 효율적으로 관리할 수 있다. 이는 다음과 같은 이점을 제공한다.

  • 운영 효율성: 수동 갱신 작업 없이 모든 서비스에 설정 변경 전파
  • 일관성: 모든 서비스가 동일한 설정을 사용하도록 보장
  • 확장성: 서비스 인스턴스가 늘어나도 추가 작업 없이 자동으로 설정 동기화
  • 유연성: 사용자 정의 이벤트를 통한 다양한 시나리오 지원

Spring Cloud Config는 설정의 중앙 집중화를, Spring Cloud Bus는 설정 변경의 자동화를, RabbitMQ는 안정적인 메시지 전달을 담당한다. 이 세 가지 기술을 함께 사용하면 마이크로서비스 운영의 복잡성을 크게 줄일 수 있다.

Spring Cloud Bus는 설정 변경 외에도 다양한 시스템 전반의 이벤트를 전파하는 데 활용할 수 있으므로, 마이크로서비스 아키텍처에서 이벤트 기반 통신의 기반으로 경우에 따라 Kafka 대신 활용할 수도 있을 것이다.