티스토리 뷰

Spring

[Spring] Spring Cloud Config 설정 파일 내용을 갱신하는 방법, Spring Cloud Bus 없이 자동 갱신하기(AutoRefresh)

망나니개발자 2022. 6. 13. 10:00
반응형

이번에는 Spring Cloud Cloud 설정 파일 주소를 SSL로 연결 설정 해보도록 하겠습니다.

 

 

 

 

1. Spring Cloud Config 설정 파일 내용을 갱신하는 방법


[ Spring Cloud Config 설정 파일 내용을 갱신하는 방법 ]

스프링 클라우드를 통해 깃 주소에서 관리하는 설정 파일에 변경이 필요할 수 있다. 그런데 별다른 설정 없이는 설정 파일이 변경되어도 변경사항이 설정 클라이언트(Spring Cloud Config Client)에 반영되지 않는다. 왜냐하면 설정 서버(Spring Cloud Config Server)에 부하를 줄이도록 애플리케이션을 실행 시점에 1번 설정 정보를 읽고 로컬에 캐싱해두기 때문이다.

만약 배포 후에 잘못된 값이 발견되었다면 설정 값 때문에 다시 배포를 해야 하므로 번거롭다. 그러므로 설정이 바뀌면 자동 갱신이 필요할 수 있는데, 이때 크게 3가지 방법을 사용할 수 있다.

  1. spring cloud client 서버들에 actuator API 호출해주기
  2. spring-cloud-bus를 사용해 이벤트 전파하기
  3. Watcher를 통해 spring cloud server에 변경 여부를 확인하기

 

 

 

 

1. spring cloud client 서버들에 actuator API 호출해주기

변경 사항을 반영하는 가장 심플한 방법은 클라이언트에 spring-boot-actuator 의존성을 추가하고 POST로 /actuator/refresh 요청을 보내는 것이다. 그러면 actuator가 설정 정보를 다시 읽고 값을 refresh한다.

이 방법은 가장 간단해서 적용하기 쉽다. 하지만 운영 중인 서버가 여러 대라면 이 작업은 상당히 번거롭다. 특히나 만약 Spring Cloud Eureka와 같이 서비스 디스커버리 기술을 사용중이지 않다면 여러 서버를 운영 중인 경우에는 적용이 어렵다. 만약 변경이 되었을 경우를 감지하고, 자동으로 변경해줄 수 있다면 좋을 것이다.

 

 

 

2. spring-cloud-bus를 사용해 이벤트 전파하기

spring-cloud-bus는 서비스 노드를 연결해 설정 정보 등의 변경을 전파해주기 위한 경량화된 메세지 브로커 프로젝트이다. 해당 프로젝트는 기본적으로 AMQP를 메세지 브로커로 사용하는데, 이것을 사용하면 변경 메세지를 받아서 값을 자동으로 갱신시킬 수 있다.

spring-cloud-bus 프로젝트는 훌륭한 기술이지만 경우에 따라서 적합하지 않을 수 있다. 왜냐하면 관리해야 하는 서버들이 늘어나는 것이기 때문이다. 이미 운영중인 서버가 많다면 부담스러울 수 밖에 없다.

 

 

 

3. Watcher를 통해 spring cloud server에 변경 여부를 확인하기

Watcher는 설정 서버에게 변경 여부를 지속적으로 물어보고 확인하는 컴포넌트이다. 일반적으로 설정 서버는 별다른 일을 하지 않도록 분리되어 있어 요청에 대한 부담도 없으며, Watcher를 사용하는 것은 간단하므로 부담이 없어 좋다.

그런데 문제는 Git으로 설정 파일을 관리하는 경우, Spring Cloud Config에서 제공하는 Watcher로는 변경 감지가 불가능하다는 것이다. 설정 서버는 설정 클라이언트에게 state와 version을 내려주는데, Git은 version이 git HEAD의 checksum에 해당한다. 하지만 Spring Cloud Config가 구현해둔 ConfigCloudWatcher는 state의 변경 여부 만을 검사해서 Git은 변경 여부 탐지가 불가능하다. 그러므로 기존에 작성되어 있던 ConfigCloudWatcher를 참고해 version의 수정 여부를 검사하는 구현체를 만들면 이를 해결할 수 있다.

public void watchConfigServer() {
    if (this.running.get()) {
        String newState = this.environment.getProperty("config.client.state");
        String oldState = ConfigClientStateHolder.getState();

        // only refresh if state has changed
        if (stateChanged(oldState, newState)) {
            ConfigClientStateHolder.setState(newState);
            this.refresher.refresh();
        }
    }
}

 

 

 

 

 

 

 

2. Git에 대한 Spring Cloud Config Watcher 구현하기


[ Git에 대한 Spring Cloud Config Watcher 구현하기 ]

  1. Watcher 구현하기
  2. Watcher를 등록할 설정 클래스 구현하기
  3. @EnableScheduling 활성화하기

 

 

1. Wathcer 구현하기

가장 먼저 version으로 refresh 여부를 결정하는 Watcher를 구현해야 한다. 이미 Spring Cloud Config가 제공하는 Watcher가 있으므로 이를 참고하면 다음과 같이 구현할 수 있다.

@Slf4j
public class CustomConfigClientWatch implements Closeable, EnvironmentAware {

    private final AtomicBoolean running = new AtomicBoolean(false);
    private final AtomicReference<String> version = new AtomicReference<>();
    private final ContextRefresher refresher;
    private final ConfigServicePropertySourceLocator locator;

    private Environment environment;

    public CustomConfigClientWatch(ContextRefresher refresher, ConfigServicePropertySourceLocator locator) {
        this.refresher = refresher;
        this.locator = locator;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @PostConstruct
    public void start() {
        running.compareAndSet(false, true);
    }

    @Scheduled(
            initialDelayString = "${spring.cloud.config.watch.git.initialDelay:10000}",
            fixedDelayString = "${spring.cloud.config.watch.git.delay:5000}"
    )
    public void watchConfigServer() {
        if (running.get()) {
            String newVersion = fetchNewVersion();
            if (newVersion == null) {
                return;
            }

            String oldVersion = version.get();
            if (versionChanged(oldVersion, newVersion)) {
                version.set(newVersion);
                refresher.refresh();
            }
        }
    }

    private String fetchNewVersion() {
        try {
            CompositePropertySource propertySource = (CompositePropertySource) locator.locate(environment);
            return (String) propertySource.getProperty("config.client.version");
        } catch (NullPointerException e) {
            log.error("Cannot fetch from Cloud Config Server: ");
        }

        return null;
    }

    private static boolean versionChanged(String oldVersion, String newVersion) {
        return !hasText(oldVersion) && hasText(newVersion)
                || hasText(oldVersion) && !oldVersion.equals(newVersion);
    }

    @Override
    public void close() {
        running.compareAndSet(true, false);
    }
}

 

 

여기서 @Scheduled 부분에 보면 2가지 속성이 있는데, 각각 다음을 의미한다. 각각 별다른 설정이 없으면 기본값이 10초, 5초로 되어 있으므로 필요에 따라 변경해주도록 하자.

  • initialDelayString: 애플리케이션 구동 후 Watcher 실행을 지연시킬 시간(ms)
  • fixedDelayString: 설정 서버로부터 변경 여부를 확인할 시간(ms)

 

 

 

2. Watcher를 등록할 설정 클래스 구현하기

그 다음은 Watcher를 빈으로 등록해주어야 한다. 이것 역시도 기존에 작성된 설정 클래스들을 따라 다음과 같이 구현할 수 있다.

@Configuration
public class CustomClientWatchConfiguration {

    @Bean
    @ConditionalOnMissingBean(ConfigServicePropertySourceLocator.class)
    @ConditionalOnProperty(name = ConfigClientProperties.PREFIX + ".enabled", matchIfMissing = true)
    public ConfigServicePropertySourceLocator configServicePropertySource(ConfigClientProperties properties) {
        return new ConfigServicePropertySourceLocator(properties);
    }

    @Bean
    @ConditionalOnProperty(name = ConfigClientProperties.PREFIX + ".enabled", matchIfMissing = true)
    public CustomConfigClientWatch configGitClientWatch(ConfigDataContextRefresher refresher, ConfigServicePropertySourceLocator locator) {
        return new CustomConfigClientWatch(refresher, locator);
    }

}

 

 

 

3. @EnableScheduling 활성화하기

우리가 구현한 Watcher는 @Scheduled를 사용해주고 있다. @Scheduled를 사용하려면 @EnableScheduling를 추가해주어야 한다. 여기서 주의할 점이 있는데, 이것을 메인 클래스에 추가하면 좋지 못하다는 것이다. 메인 클래스에 이러한 설정 정보를 주는 것은 테스트 성능에 영향을 줄 수 있는데, 자세한 내용은 이 링크의 내용을 참고하도록 하자. (예제 코드에서는 편리하게 메인에 작성해주었다.)

추가적으로 만약 경우에 따라 자동으로 설정을 가져오는 것을 끄고 키고 싶다면, 해당 값을 캐시로 관리하고 설정 파일 중간에 캐시로부터 값을 가져오도록 설정해주면 될 것 같다.

 

 

 

 

 

클라우드 설정값을 자동 갱신시키는 것은 편리함을 얻을 수 있지만, 시스템의 문제 상황에서는 장애 파악을 어렵게 만들 수 있습니다. 일반적으로 문제가 생긴 서버의 상태를 그대로 보존해야 제대로 된 원인을 파악하는 것이 가능한데, 자동 갱신을 사용해버리면 서버가 상태를 가지기 때문에(stateful) 이러한 장애 회복과 관련된 부분에서는 단점이 될 수 있습니다.

그 외에도 Config Server를 사용하면서 주의할 점이 있는데, 관련 내용은 이 포스팅을 참고해주세요!  감사합니다:)

 

 

 

 

관련 포스팅

  1. Spring Cloud Config 도입하기 및 private 레포지토리 SSL로 연결 설정 및 privateKey 암호화
  2. Spring Cloud Config 설정 파일 내용을 갱신하는 방법, Spring Cloud Bus 없이 자동 갱신하기
  3. Spring Cloud Config 사용 시의 주의사항 및 에러 해결 (Internal Server Error, RSA key with SHA-1)

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함