spring boot 애플리케이션 환경설정을 Spring Cloud Config로 관리하고 있었습니다.
환경설정 파일(ex. application.yml)은 github private repository에 저장하고 Spring Cloud Config가 애플리케이션 실행 시 맞는 환경설정 파일을 가져와 적용해줍니다.
그런데 환경설정을 수정할때마다 변경사항을 적용하기 위해 /actuator/refresh API 를 호출해야했습니다.
이는 환경설정이 빈번하게 수정되는 개발기간에 상당히 귀찮았고, 게다가 MSA에서 여러 애플리케이션들의 auctuator API를 호출하는 것도 비효율적이었습니다.
요구사항은 다음과 같았습니다.
1. 레포지토리에 push하면 자동으로 수정된 환경설정이 적용될 것
2. 한번의 동작으로 여러 애플리케이션들에 변경사항이 적용될 것
방법을 찾아보다가 Spring Cloud Config Monitor와 Spring Cloud Bus를 사용하는 방법을 발견했습니다.
Spring Cloud Bus
공식문서에서 설명하는 Spring Cloud Bus는 다음과 같습니다.
Spring Cloud Bus는 분산 시스템의 노드를 경량 메시지 브로커와 연결합니다. 그러면 상태 변경(ex. 환경설정 변경) 또는 기타 관리 지침을 브로드캐스트하는 데 사용할 수 있습니다.
AMQP, Kafka 구현체가 포함되있고, 또는 Spring Cloud Stream 바인더가 전송으로 즉시 작동합니다.
즉, 하나의 메시지를 보내면 연결된 모든 서비스 인스턴스가 동시에 이 메시지를 받아 처리할 수 있습니다.
마침 kafka를 사용 중이어서 쉽게 적용할 수 있었습니다.
먼저 Spring Cloud Config 애플리케이션의 환경설정을 다음과 같이 수정합니다.
# .yml
spring:
kafka:
bootstrap-servers: <kafka broker 주소>
cloud:
bus:
enabled: true
저는 Spring Kafka 라이브러리를 사용했습니다.
Spring Cloud Config는 기본적으로 Spring Cloud Bus를 지원하기 때문에 사용할지 안할지만 설정해주면 됩니다.
그리고 클라이언트 애플리케이션에 Spring Cloud Bus 의존성을 추가합니다.
implementation 'org.springframework.cloud:spring-cloud-starter-bus-kafka'
클라이언트 애플리케이션이 메시지를 받아야하니까 마찬가지로 kafka 설정을 환경설정에 추가해줍니다.
# .yml
spring:
application:
name: member-service
profiles:
active: none
config:
import: optional:configserver:<config 서버 주소>
cloud:
config:
profile: ${PROFILE}
kafka:
bootstrap-servers: <kafka broker 주소>
이로써 요구사항 2번은 충족했습니다.
Spring Cloud Config Monitor
Spring Cloud Config Monitor 라이브러리를 사용하면 소스코드 저장소의 설정 변경을 감지하고 관련 애플리케이션들에게 자동으로 설정 갱신을 알려줄 수 있습니다.
/monitor 엔드포인트에 POST 요청으로 수동 갱신이 가능합니다.
webhook을 통해 저장소의 변경 이벤트를 수신하면 Spring Cloud Bus를 통해 관련 애플리케이션들에게 RefreshRemoteApplicationEvent를 전송합니다.
기본적으로 변경 감지된 파일 이름과 일치하는 이름의 애플리케이션에 알립니다. (application.properties가 변경되면 모든 애플리케이션에 알립니다.)
/monitor 엔드포인트를 github 레포지토리에서 webhook으로 설정하면 변경이 발생했을때 자동으로 알려줄 수 있습니다.
Spring Cloud Config 애플리케이션에 spring-cloud-config-monitor 의존성을 추가해줍니다.
implementation 'org.springframework.cloud:spring-cloud-config-monitor'
이제 github 레포지토리에 webhook을 설정합니다.
Payload URL에는 Spring Cloud Config 애플리케이션이 배포된 주소/monitor를 입력합니다.
저는 config 레포지토리에 push 이벤트가 발생했을때만 변경사항이 전파되길 원했기 때문에 `just the push event`를 선택했습니다.
그리고 클라이언트 애플리케이션에 @RefreshScope를 달아줍니다.
@SpringBootApplication
@RefreshScope
public class MyApplication {
//...
}
@RefreshScope가 적용된 빈은 구성 속성이 변경되면 다시 생성되어 새로운 값을 반영합니다.
만약 @RefreshScope를 적용하지 않은채로 데이터베이스 주소를 변경했다면, 기존에 로드된 값이 계속 사용되므로 새로운 주소로 연결되지 않습니다. 이로 인해 애플리케이션이 데이터베이스에 접근할 수 없게 됩니다.
위 예시 코드에서는 애플리케이션의 시작점인 메인 클래스에 적용하여 모든 bean이 갱신됩니다.
환경설정과 관련된 bean들만 갱신하면 성능에 미치는 영향을 최소화할 수 있습니다.
이로써 요구사항 1도 충족했습니다.
이제 환경설정 레포지토리에 변경 사항을 push하면 작동 중인 애플리케이션들에 자동으로 변경 사항을 갱신합니다.
다음에는 환경설정 파일과 관련된 bean들만 갱신되도록 더 세밀하게 @RefreshScope를 적용해야겠습니다.
참고
https://spring.io/projects/spring-cloud-bus#overview
Spring Cloud Bus
Spring Cloud Bus links nodes of a distributed system with a lightweight message broker. This can then be used to broadcast state changes (e.g. configuration changes) or other management instructions. AMQP and Kafka broker implementations are included with
spring.io
Spring Cloud Config
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments. The concepts o
docs.spring.io
'Springboot' 카테고리의 다른 글
[트러블 슈팅] Spring Cloud Gateway CORS 설정하기 (0) | 2024.12.02 |
---|---|
[트러블 슈팅]N+1 해결하기 (3) (0) | 2024.02.24 |
[트러블 슈팅]N+1 해결하기 (2) (0) | 2024.02.24 |
[트러블 슈팅]N+1 해결하기 (1) (0) | 2024.02.24 |
[트러블 슈팅]LazyInitializationException 간단 해결법 (0) | 2024.02.24 |