올리브영 테크블로그 포스팅 Spring Cloud Config & Bus-Refresh 도입기
Tech

Spring Cloud Config & Bus-Refresh 도입기

무중단 마이크로서비스 오케스트라 지휘법

2025.11.04

🎶 마이크로서비스 오케스트라 지휘법: Spring Cloud Config로 실시간 설정 변경하기

배포 없이 실시간으로 설정을 바꾸는 지휘자의 비밀 노트


안녕하세요! 올리브영 상품통합프로젝트의 하모니를 책임지고 있는 불광동꿀주먹👊입니다.

"설정값 딱 하나 바꾸려는데, 전체 서버를 다 재시작해야 한다고요? 그게 최선인가요?" 🤔

이런 고민, 개발자라면 한 번쯤 해보셨을 겁니다. 저희 팀도 얼마 전까지 설정 파일의 작은 수정 하나 때문에 전체 오케스트라의 연주(서버 배포)를 멈춰야 하는 아찔한 상황을 겪곤 했죠. 각자 다른 악보(설정)를 보고 연주하는 연주자들처럼, 서비스마다 설정이 꼬이는 일도 상상하기 싫은 현실이었습니다.

하지만 이 모든 혼란을 잠재울 멋진 지휘봉을 발견하며 저희 프로젝트는 새로운 국면을 맞이했습니다. 바로 Spring Cloud Config Server와 Bus-Refresh를 도입한 것이죠. 🎼

설정 변경을 위해 더 이상 서비스 전체를 멈추지 않아도 되는, 우아하고 조화로운 저희 팀의 개발 여정을 여러분께 공유해 드립니다. 자, 이제 저희 오케스트라의 변화를 함께 감상해 보시죠! 🚀

🎼 문제의 시작: 조율되지 않는 오케스트라

저희는 상품통합프로젝트를 진행하면서 여러 마이크로서비스(MSA)를 운영하고 있습니다. 그러다보니 여러 프로젝트가 공통으로 사용하는 설정값, 예를 들면 온라인 상품 조회 API가 변경될 때마다 문제가 발생했죠.

하나의 설정을 바꾸기 위해 연관된 모든 서비스를 다시 빌드하고 배포하는 과정은 비효율의 극치였습니다. 연주 중간에 악보 한 장을 바꾸려고 전체 오케스트라를 무대 뒤로 보내는 것과 같았죠.

저희에게는 모든 연주자(서비스)에게 변경된 악보(설정)를 실시간으로 전달해 연주의 흐름을 끊지 않을 방법이 절실했습니다.

💡 우리의 지휘봉을 찾아서: 해결책 모색

이러한 문제를 해결하기 위해 저희는 Spring Cloud Config Server를 도입했습니다.

이 솔루션은 분산된 여러 서비스의 설정값(악보)을 Git과 같은 중앙 저장소에서 통합 관리하고, 변경이 생겼을 때 각 서비스에 실시간으로 동기화하는 지휘자 역할을 합니다.

다양한 솔루션을 비교 검토한 결과, Spring Cloud Config Server가 저희 오케스트라에 가장 적합한 지휘봉이라고 판단했습니다.

특히 Git을 통한 버전 관리 및 롤백 기능, Spring Cloud Bus와 연동하여 여러 서비스에 한 번에 설정을 전파하는 bus-refresh 기능 은 저희에게 꼭 필요한 기능이었습니다.

마지막까지 고민했던, AWS Parameter Store 와의 비교자료는 아래와 같습니다.

Spring Cloud Config Server 🆚 AWS Parameter Store

항목 Spring Cloud Config Server AWS Parameter Store
기본 기능 Git 기반 설정파일 외부화, 분산 어플리케이션 구성 관리 Key-Value 설정 저장, 버전관리, IAM 인증
특징 Git, Vault 등 외부 저장소와 연동, 복잡한 구성 가능 AWS Managed, IAM 권한 기반 접근 제어
장점 강력한 설정 파일 구조화 및 프로파일별 관리 서버리스, 쉬운 접근, 고가용성
단점 자체 구성 필요, 운영 오버헤드 발생 가능 Git 버전관리 불가, 설정 계층 표현이 제한적

🏗️ 조화로운 연주를 위한 설계도: 아키텍처

image1
Spring Cloud Config & Bus-Refresh 도입 아키텍처

저희는 위와 같은 아키텍처를 통해 실시간 설정 변경 시스템을 구축했습니다.

전체 연주(프로세스)는 이렇게 진행됩니다.

  1. 작곡가 (AWS General User) 가 악보(설정)를 수정하여 Git에 Push합니다.
  2. 지휘자 (Spring Cloud Config Server) 가 TeamCity의 트리거를 통해 변경을 감지합니다.
  3. 지휘자는 /actuator/busrefresh 엔드포인트를 호출하여 "악보가 바뀌었어!"라고 외칩니다.
  4. 이 외침은 음파 (Amazon MQ) 를 통해 모든 연주자 (Spring Boot MicroService) 에게 순식간에 퍼져나갑니다.
  5. 각 연주자는 새로운 악보를 받아 즉시 연주에 반영합니다.

🛠️ 악기 튜닝하기: 상세 구현 과정

지휘봉을 손에 넣었으니, 이제 각 악기(서비스)를 세심하게 튜닝할 차례입니다.

적용 범위

이 시스템은 API 설정값이나 DB Endpoint처럼 외부에서 주입받는 값들에 적용하기 좋습니다. (단, DB Endpoint와 같은 DataSource 설정을 실시간으로 변경하려면, 해당 DataSource 빈(Bean)에도 @RefreshScope를 적용하고 Spring 2.x 이상 버전의 DataSource 구성 방식을 사용해야 합니다.)

하지만 주의할 점도 있습니다. Java나 Kotlin의 DTO 클래스 필드처럼 컴파일 시점에 구조가 고정되는 경우에는 적용할 수 없습니다. 연주 중간에 바이올린을 첼로로 바꿀 수 없는 것과 같은 이치죠.

Spring의 @RefreshScope는 빈(Bean)을 새로고침하는 수준이지, 클래스의 구조 자체를 바꾸지는 못하기 때문입니다.

⚙️ 설정 방법

🚨 주의사항 : Spring Boot의 버전에 따라 설정 방법이 상이합니다

https://spring.io/projects/spring-cloud

해당 사이트를 참고하여, 각 스프링부트 버전에 대응하는 spring-cloud-dependencies:2020.0.3 버전을 설정해주셔야 합니다

image2
Spring Cloud Config Dependencies

Spring Boot 2.3.x 이하:

  • bootstrap.yml 파일 필요
  • spring.cloud.config.uri 설정 방식

Spring Boot 2.4.x 이상:

  1. build.gradle.kts (domain, interface패키지 하위) 의존성 추가

    dependencies {
       implementation("org.springframework.boot:spring-boot-starter-actuator")
       implementation("org.springframework.cloud:spring-cloud-starter-config")
       implementation("org.springframework.cloud:spring-cloud-starter-bus-amqp")
    }
    
    dependencyManagement {
        imports {
            mavenBom("org.springframework.cloud:spring-cloud-dependencies:2020.0.5")
        }
    }
  2. application.yml 또는 application-.yml에 아래와 같이 설정

    spring:
      application:
        name: test-application
      config:
        import: optional:configserver:http://spring-cloud-config-server.com
          activate:
            on-profile: "qa"
  3. 설정 적용을 위한 actuator endpoint 활성화

    management:
      endpoints:    
        web:      
          exposure:        
            include: health, info, refresh, busrefresh
  4. rabbitMQ 설정 추가(계정정보는 config-server에서 암호화되어 설정)

    rabbitmq:    
      host: b-1234-4567-8900-abcd-123456789.mq.ap-northeast-2.on.aws    
      port: 5671    
      virtual-host: /    
      ssl:      
        enabled: true         `
  5. 호출하려는 클래스에 @RefreshScope 어노테이션 추가, @Value 어노테이션으로 값 주입

    @RefreshScope 
    @Service 
    class TestServiceImpl(    
        val testRepository: TestRepository 
    ) : TestService {      
        @Value("\${config.goods-api-url}")   
        lateinit var goodsApi: String 
    }   

✨ 클라이맥스: 실시간 변경의 순간

모든 튜닝이 끝나고, 드디어 지휘를 시작할 시간입니다. 개발자가 Git에 변경된 설정값을 Push하자, TeamCity가 이를 감지하여 busrefresh를 자동으로 호출합니다.

BusRefresh 수동 호출 Teamcity Trigger 설정 자동호출
curl --location --request POST 'http://spring-cloud-config-server.com/actuator/busrefresh' github push Trigger로 동작하여 actuator/busrefresh 호출!
image3

곧이어 서비스 로그에는 변경된 설정 키들이 새로고침되었다는 메시지가 나타납니다.

2025-06-21 01:45:19.733 [INFO] (RefreshListener.java:50) Keys refreshed [config.goods-api-url] [cite: 149]

그리고 마법처럼, 서버 재시작 없이 API 응답값이 즉시 변경된 것을 확인할 수 있었습니다.

이로써 단순 설정 변경을 위한 배포 시간이 기존 평균 20분에서 1분 이내로 단축되었고, 긴급 상황 발생 시 운영 서버의 재시작 부담 없이 신속하게 대응할 수 있는 안정성을 확보했습니다.

이 모든 과정이 끝나면 Slack으로 알림 메시지가 전송되어, 모든 오케스트라 단원들이 변경 사항을 인지하게 됩니다.

Config Server 알럿 메시지
Config Server 알럿 메시지(Config 변경 내역 전송)
Config Client 알럿 메시지
Config Server 알럿 메시지(Config 변경 내역 전송)

🚀 앙코르: 표준화와 다음 연주를 향하여

저희는 이 경험을 바탕으로, 해당 시스템 구성을 올리브영 개발센터의 표준 아키텍처 템플릿(olive-plate)에 적용했습니다.

이제 누구나 이 강력한 지휘봉을 사용하여 조화로운 마이크로서비스 오케스트라를 구성할 수 있게 된 것이죠.

급변하는 기술의 세계 속에서, 마치 시간에 쫓기는 토끼처럼 쉼없이 달려가던 저희는 잠시 멈춰 서서 이 오케스트라를 조율하는 법을 배운 셈입니다.

이제 저희의 오케스트라는 지휘자의 손짓 하나(git push)에 일사불란하게 연주를 바꾸는 환상적인 하모니를 자랑하게 되었습니다.

저희의 다음 연주가 궁금하시다면, 올리브영 기술 블로그를 계속 주목해주세요! 🎶

References

Spring Cloud Config마이크로서비스 (MSA)실시간 설정 변경 (Dynamic Configuration)
올리브영 테크 블로그 작성 Spring Cloud Config & Bus-Refresh 도입기
🙈
불광동꿀주먹 |
Back-end Engineer
버티면 다 되는거야😵