[스프링] 스프링 클라우드 - 스프링 클라우드 태스크와 스프링 배치

스프링 클라우드 태스크

클라우드 네이티브 기반 시스템은 장애 허용성(fault tolerance)과 고가용성(high availability)을 제공하기 위해 프로세스 실행이 종료되지 않도록 유지하는 것을 목적으로 설계되어 있다. 컨테이너 기술과 컨테이너 오케스트레이션 시스템을 사용함으로써 컨테이너 형태의 프로세스를 손쉽게 생성하고 클러스터로 구성된 시스템에 장애가 발생하더라도 페일오버(failover)를 통해 정상적으로 운영하기 위한 서버 배포, 로드 밸런싱 등의 과정이 손쉽게 가능해진다.

특정 프로세스가 실행 중 비정상적으로 종료되더라도 재시작하여 다시 원래의 의도한 상태로 서비스가 유지되도록 한다. 대부분의 클라우드 플랫폼은 프로세스가 종료된 후 자동으로 다시 시작되지 않는 경우 다시 실행할 수 있는 방법을 제공하지만, 프로세스 실행의 결과는 일반적으로 소비 가능한 형태(예: 실행 결과를 기록하고 그 기록을 다른 목적으로 사용)로 유지(영속화)되지는 않는다.

프로세스 중에는 지속적으로 실행되어야 하는 프로세스도 있지만 시작, 실행 및 종료라는 라이프사이클을 가지는 프로세스도 존재한다. 대표적인 예로 데이터의 일괄 처리 작업을 수행하는 배치 애플리케이션이 있다. 배치 애플리케이션은 시작 후 레코드들을 처리한 후에 정상적으로 종료되는 것이 주 목적이며 따라서 단기(short-lived) 실행 프로세스라고 볼 수 있다. 배치 애플리케이션을 웹 애플리케이션과 통합하여 상시 동작 중인 프로세스 내에서 스케줄링을 통해 배치 처리 작업이 필요할 때 수동으로 실행되도록 할 수도 있다.

라이프사이클을 가지는 프로세스는 단순히 헬스 체크를 통해 서비스가 다운되었을 경우 재시작하는 방법으로는 관리가 어렵다. 스프링 클라우드 태스크(spring cloud task)의 주 목적은 수명이 짧은 프로세스(쿠버네티스 플랫폼의 경우 파드)를 실행하고 실행 결과(실패 또는 완료)를 기록할 수 있는 기능을 제공하는 것이다. 프로세스의 실행 결과를 기록하는 것은 클라우드 환경 뿐만 아니라 기존 배포 모델에 대해서도 유용할 수 있다. 크론 스케줄러를 사용하여 스프링 애플리케이션을 실행하는 경우 각각의 실행 결과 모니터링이 필요한 경우가 이에 해당한다.

대부분의 웹 애플리케이션으로 대표되는 대부분의 장기(long-lived) 실행 프로세스는 라이프사이클 이벤트(일련의 프로세스 상태 변경 이벤트)를 저장하지 않지만 스프링 클라우드 태스크는 프로세스의 라이프사이클 이벤트를 기록한다는 점에서 차이가 있다. 쿠버네티스 플랫폼이 자체적으로 파드들의 실행 상태에 대한 기록을 처리하지만 이러한 데이터를 영속화하고 다른 기능을 위해 제공하려면 추가적인 기능 구현 및 API 연동이 필요하다.

일반적으로 클라우드 네이티브 애플리케이션의 경우 애플리케이션의 상태를 관리 및 저장하지 않는 프로세스로 간주하고 실행하는 스테이트리스(상태 비저장) 프로세스(stateless process)이다. 애플리케이션의 상태를 따로 저장하고 관리해야 한다면 애플리케이션 외부에 명시적으로 애플리케이션 상태를 저장할 수 있는 외부 저장소(예: 데이터베이스, 파일 시스템)를 구성하여 컨테이너의 라이프사이클과 애플리케이션 상태를 서로 분리해야 한다. 스프링 클라우드 태스크는 별도의 데이터베이스를 통해 태스크(task)의 라이프사이클 이벤트를 애플리케이션 상태로 저장함으로써 프로세스를 스테이트풀(상태 저장) 프로세스(stateful process)로 만든다.


스프링 클라우드 태스크 애플리케이션 구현 및 요구사항

스프링 클라우드 태스크 애플리케이션은 프로세스를 상태 저장으로 만들기 위해 데이터베이스를 반드시 필요로 한다. 이때 관계형 데이터베이스를 사용하여 실행된 태스크 애플리케이션의 결과를 저장한다. 데이터베이스 없이 태스크 애플리케이션을 개발 및 실행할 수도 있지만 이 경우 태스크 애플리케이션의 실행과 관련된 데이터를 저장하고 이를 활용할 수는 없다.

스프링 클라우드 태스크는 spring-cloud-starter-taskspring-cloud-task-core 의존성을 필요로 한다. 관련 의존성을 추가한 후 @SpringBootApplication 어노테이션이 지정된 메인 클래스에 추가적으로 @EnableTask 어노테이션을 지정한다. @EnableTask 어노테이션은 스프링 애플리케이션에 스프링 클라우드 태스크의 기능을 적용하는 부트스트랩 역할을 수행한다. SimpleTaskConfiguration 클래스는 스프링 태스크 기능을 활성화하고 이를 사용하기 위한 공통 구조를 제공하는 기본 구성 클래스이다. TaskConfigurer 인터페이스를 구현하면 기능 구성의 사용자화가 가능하다.

spring-cloud-starter-task 의존성을 추가하고 @EnableTask 어노테이션를 지정하면 관련된 모든 빈의 기능이 자동으로 구성된다. 이러한 구성에는 TaskRepository 빈과, 관련 인프라를 등록하는 것이 포함된다. TaskRepository는 태스크 애플리케이션의 실행과 관련된 데이터를 저장하는 리포지토리 구현체 역할을 수행한다.

스프링 클라우드 태스크 애플리케이션 또한 스프링 부트 기반이며, 애플리케이션 루트에서 메이븐의 mvn spring-boot:run 명령어나 그래들의 gradle bootRun 명령어를 사용하여 실행할 수 있다.

애플리케이션 프로퍼티 설정 방법도 기존 스프링 부트와 다르지 않다. src/main/resources 경로의 application.properties 파일에 두 가지 프로퍼티를 구성한다.

  • application.name: 애플리케이션의 이름을 설정한다. 이 이름은 태스크 이름이 된다.
  • logging.level: 태스크 실행 시 로깅 레벨을 설정한다.


스프링 클라우드 태스크도 스프링 부트가 제공하는 *Runner 인터페이스(CommandLineRunner 또는 ApplicationRunner)를 사용하여 모든 로직을 부트스트랩할 수 있다. 태스크의 라이프사이클은 *Runner 인터페이스의 run() 메서드가 실행되기 전부터 모두 실행 완료되는 시점까지를 말한다. 태스크가 시작되면, CommandLineRunner 또는 ApplicationRunner 구현이 실행되기 전에, 태스크의 시작 이벤트를 기록하기 위해 TaskRepository에 엔티리(entry)를 생성한다. 이 엔트리에는 일반적으로 실행 ID, 시작 시간 및 태스크에 대한 기타 관련 메타데이터와 같은 정보가 포함되어 있다.

태스크의 시작 이벤트는 스프링 프레임워크의 SmartLifecyclestart() 메서드를 통해 트리거된다. 시작 이벤트는 CommandLineRunner 또는 ApplicationRunner 구현을 실행하기 전에 모든 빈이 사용할 준비가 되어 있다는 것을 시스템에게 알린다. 태스크 실행 기록은 ApplicationContext의 부트스트랩이 성공적으로 이루어졌을 때만 발생한다. 부트스트랩에 실패하면 기록되지 않는다.

스프링 부트의 모든 *Runner 인터페이스의 run() 메서드 호출이 완료되거나 ApplicationContext가 실패하는 경우(ApplicationFailedEvent 발생), 태스크 실행 결과가 데이터베이스에 저장된다.


스프링 클라우드 태스크와 스프링 배치의 통합

스프링 배치 애플리케이션을 실행하는 방법은 다양하다. 웹 애플리케이션 내에 스프링 배치를 포함한 후 내장된 자바 스케줄러 의해 주기적으로 잡을 실행하거나 외부 HTTP 요청을 통해 배치 잡을 실행할 수 있다. 또는 쿠버네티스의 크론잡(CronJob) 컨트롤러를 사용하여 단순히 배치 애플리케이션을 주기적으로 실행 및 종료할 수 있다. 즉, 클라우드 환경에서 스프링 배치 애플리케이션을 실행하려는 경우 스프링 클라우드 태스크와 반드시 통합해야 하는 것은 아니다. 스프링 배치 애플리케이션과 통합하는 경우 스프링 클라우드 태스크가 제공하는 기능링크은 다음과 같다.

  • 잡 실행을 태스크 실행과 연결링크: 배치 잡 실행을 태스크 실행과 연결하여 여러 잡 실행을 개별적으로 추적
  • 원격 배치 파티셔닝링크: 스프링 클라우드 디플로이어(spring cloud deployer)를 통해 스프링 배치 애플리케이션의 잡 실행을 동기적 또는 비동기적으로 파티셔닝
  • 스프링 배치 이벤트 방출링크: 스프링 배치의 리스너를 기반으로 스프링 클라우드 스트림의 채널에 메시지 방출
  • 단일 스텝 배치 잡 스타터 제공링크: 스프링 클라우드 태스크에 포함된 스타터를 사용하여 단일 스텝으로 동작하는 스프링 배치 애플리케이션을 간편하게 개발


잡 파라미터 설정

*Runner 인터페이스 구현을 사용하여 태스크 실행 시 잡 파라미터를 설정하여 잡을 실행하도록 만들 수 있다. run() 메서드에서 잡 파라미터를 설정하고 잡을 실행한다.

ApplicationRunner 인터페이스를 구현하는 예는 다음과 같다.

@Component
@RequiredArgsConstructor
public class BatchApplicationRunner implements ApplicationRunner {
    private final JobLauncher jobLauncher;
    private final Job job;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // JobParametersBuilder를 사용하여 JobParameters 구성
        JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
        
        // 현재 날짜와 시간을 파라미터로 추가
        jobParametersBuilder.addLong("currentTimeMillis", System.currentTimeMillis());
        
        // JobParameters 객체 생성
        JobParameters jobParameters = jobParametersBuilder.toJobParameters();
        
        // JobLauncher를 통해 잡 실행
        jobLauncher.run(job, jobParameters);
    }
}


참고

Comments