ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Batch 살짝 알아보기-2
    개발/Spring 2022. 2. 7. 11:10

    스프링 공식문서를 보면서 대략적인 개념을 잡고나서 잘 정리되어 있다는 블로그 글 시리즈를 보면서 좀 세부적이 내용에 대해 알아보았다. 그리고 따라하기 예제가 있는 블로그 글을 참고하여 실습을 진행해 보았다.

    배치 더 알아보기

    스프링 배치를 실행시키면 연결된 DB에 메타 정보 테이블이 설정되어야 한다. 이것은 처음에 DB에 스키마를 보내 설정해주어야 한다. (H2의 경우 자동으로 설정됨) 해당 내용은 의존성 모듈의 schema-mysql.sql 파일 등으로 DB 벤더마다 설정 파일이 들어있다. 이것을 DB을 생성하고 테이블을 생성해주어야 한다.

    Job, Step

    스프링배치에서 Job은 하나의 배치 작업 단위이다. 하나의 Job 안에 여러 Step이 존재할 수 있고, Step 안에 Tasklet 혹은 Reader & Processor & Writer 묶음이 존재할 수 있다. Tasklet과 Reader & Processor & Writer 묶음은 같은 레벨이다.

    // 설정파일
    public class SimpleJobConfiguration {
    	// ...
        @Bean
        public Job simpleJob() {
            return jobBuilderFactory.get("simpleJob")
                    .start(simpleStep1())
                    .build();
        }
    
        @Bean
        public Step simpleStep1() {
            return stepBuilderFactory.get("simpleStep1")
                    .tasklet((contribution, chunkContext) -> {
                        log.info(">>>>> This is Step1");
                        return RepeatStatus.FINISHED;
                    })
                    .build();
        }
    }

    블로그에 나와있던 예시인데 위의 예시처럼 reader, processor, writer를 분리하지 않고 하나의 tasklet 안에서 설정할 수 있다. Tasklet 인터페이스에 들어가보면 트랜잭션 단위 내에[서 필요한 프로세스를 처리한다고 되어있고 FINISHED, CONTINUABLE 을 리턴하거나exception을 던져야 한다고 적혀있다.

    하나의 Job은 여러 Step을 가질 수도 있으므로 Job 실행시 start, next 등으로 여러 스탭을 넣을 수 있다. 

        @Bean
        public Job userJob(JobBuilderFactory jobBuilderFactory) {
            return jobBuilderFactory.get("userJob")
                    .preventRestart()
                    .start(dataSettingStep())
                    .next(inactiveUserStep())
                    .build();
        }

    Flow, Decider

    조건별 어떤 step을 실행할 건지 설정이 가능하다. 이때 Flow를 사용하는 듯 싶다. 참고 글을 보면 Configuration 내용을 찾아볼 수 있다. 해당 글을 읽다보면 BatchStatus와 ExitStatus의 차이를 아는 것이 중요하다고 한다. BatchStatus는 Job 또는 Step 의 실행 결과를 Spring에서 기록할 때 사용하는 Enum이며 ExitStatus는 Step의 실행 후 상태를 의미한다. Spring Batch는 기본적으로 ExitStatus의 exitCode는 Step의 BatchStatus와 같도록 설정이 되어 있다고 한다.

    Step들의 Flow속에서 분기만 담당하는 Decider 타입이 있다. 이것 역시 Configuration을 통해 설정하며 Decider는JobExecutionDecider를 상속하여 개발자가 구현하여 등록한다.

    Scope

    Scope는 외부 파라미터를 주입시킬 때 사용한다. @JobScope는 Step 선언문에서 사용 가능하고, @StepScope는 Tasklet이나 ItemReader, ItemWriter, ItemProcessor에서 사용할 수 있다. 이것들은 프록시로 동작하는 듯 하다. 그래서 ItemReader에서 사용시 주의해야한다. 빈 등록 시점을 scope가 실행되는 시점으로 지연시킨다는 사실을 잘 염두하고 사용해야 한다.

    • StepScore : Step 실행 시점에 Spring bean으로 생성
    • JobScope: Job 실행 시점에 Spring bean으로 생성

    Chunk size, Page size

    데이터를 한번에 읽는 Chunk 단위로 트랜잭션을 다루는 것을 의미한다. Chunk size는 트랜잭션 단위를 의미하며, Page size는 한번에 조회할 Item의 양을 의미한다. 기본적으로 Page size는 10으로 설정되어 있고, Chunk size와 Page size가 다를 때, Chunk size가 100이더라도 10번의 트랜잭션이 수행될 수 있다. 이것은 JPA 영속성 컨텍스트에서 문제가 될 수 도 있다고 한다. 100개를 조회시 chunk단위가 100이더라도 page size로 인해 트랜잭션이 10개로 나뉘져 맨 뒤의 조회만 영속성 컨텍스트가 유지되어 지연 로딩에서 문제가 발생할 수 있다고 한다. chunk size와 page size의 갯수를 똑같이 맞춰주는 것으로 해당 문제를 해결할 수 있다고 한다.

    CursorItemReader, PagingItemReader

    CursorItemReader 방식은 Stream을 사용한다. CursorItemReader를 사용할 때는 Database와 SocketTimeout을 충분히 큰 값으로 설정해야만 한다. Cursor는 하나의 Connection으로 동작하며, Batch가 끝날때까지 사용된다. 따라서 Batch가 끝나기전에 Database와 어플리케이션의 Connection이 먼저 끊어져 문제가 발생할 수 있다. Batch 수행 시간이 오래 걸리는 경우에는 PagingItemReader를 사용하는게 낫다고 한다.

    Paging의 경우 한 페이지를 읽을때마다 Connection을 맺고 끊기 때문에 아무리 많은 데이터라도 타임아웃과 부하 없이 수행될 수 있다. 여러 쿼리를 실행하여 각 쿼리가 결과의 일부를 가져 오는 처리 방법을 Paging 이라고 한다. 각 페이지마다 새로운 쿼리를 실행하므로 페이징시 결과를 정렬하는 것이 중요하며 데이터 결과의 순서가 보장될 수 있도록 order by가 권장된다고 한다.

    CursorItemReader와 PageItemReader 설정 중 크게 다른 것은 쿼리 부분이다. JdbcCursorItemReader를 사용할 때는 단순히 String 타입으로 쿼리를 생성하지만, PagingItemReader에서는 PagingQueryProvider를 통해 쿼리를 생성한다.

    참고

    '개발 > Spring' 카테고리의 다른 글

    Spring Batch 살짝 알아보기-3  (0) 2022.02.13
    Spring Batch 살짝 알아보기-1  (0) 2022.02.07

    댓글

Designed by Tistory.