본문 바로가기

SpringBoot

[Spring Batch] Tasklet vs Chunk 간단 정리

Spring Batch를 다루다 보면 Step을 구성하는 두 가지 큰 갈래길, TaskletChunk를 마주하게 됩니다. "그냥 대충 쓰면 되는 거 아냐?"라고 생각했다면 오산! 이 둘은 용도가 명확히 다릅니다.

 


1. Tasklet 모델: "단순하고 명료하게"

Tasklet은 말 그대로 '하나의 작업(Task)'을 처리하는 데 집중합니다. 복잡한 읽기/쓰기 과정 없이, "이거 실행하고 끝내!" 할 때 딱입니다.

  • 언제 쓸까?: 임시 파일 삭제, DB 프로시저 호출, 슬랙 알림 발송 등
  • 특징: execute 메서드 하나로 모든 로직이 끝납니다.

📝 코드 예제: 오래된 로그 정리하기

Tasklet 인터페이스를 구현하여, 7일 지난 로그 파일을 지우는 작업을 만들어 봅시다.

@Slf4j
@Component
public class LogCleanupTasklet implements Tasklet {

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        log.info(" [Step 1] 시스템 로그 정리 작업을 시작합니다.");

        // 비즈니스 로직: 7일 지난 로그 삭제 
        int deletedCount = deleteOldLogs(7); 
        
        log.info("총 {}개의 오래된 로그 파일이 삭제되었습니다.", deletedCount);

        // FINISHED를 반환해야 다음 단계로 넘어감 (CONTINUABLE은 반복)
        return RepeatStatus.FINISHED;
    }

    private int deleteOldLogs(int days) {
        // 실제 삭제 로직...
        return 100; // 테스트용 리턴
    }
}

 

설정(Configuration)은 이렇게:

 
@Bean
public Step logCleanupStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return new StepBuilder("logCleanupStep", jobRepository)
            .tasklet(new LogCleanupTasklet(), transactionManager) // Tasklet 등록
            .build();
}

 

 


2. Chunk 모델: "대용량 처리의 정석"

데이터가 10만 건, 100만 건 넘어간다면? 이걸 한 번에 메모리에 올리면 서버가 터집니다.

이때 등장하는 게 Chunk(덩어리) 지향 처리입니다.

데이터를 조금씩 쪼개서 "읽고(Read) → 가공하고(Process) → 쓰는(Write)" 구조입니다.

  • 언제 쓸까?: 대량 회원 등급 산정, 일일 정산, 데이터 마이그레이션 (ETL)
  • 핵심: Chunk Size만큼 트랜잭션을 끊어서 처리합니다. (실패해도 그 덩어리만 롤백!)

📝 코드 예제: 휴면 회원 전환 배치

회원 정보를 100명씩 읽어서(Read), 휴면 상태로 변경하고(Process), DB에 저장(Write)하는 흐름입니다.

@Bean
public Step inactiveUserStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return new StepBuilder("inactiveUserStep", jobRepository)
            // [핵심] 100개 단위로 끊어서 처리 (트랜잭션 범위 = 100)
            // <입력타입(User), 출력타입(User)>chunk(사이즈)
            .<User, User>chunk(100, transactionManager)
            
            .reader(inactiveUserReader())      // 1. 읽기 (DB에서 대상 조회)
            .processor(inactiveUserProcessor()) // 2. 가공 (상태 변경 로직)
            .writer(inactiveUserWriter())      // 3. 쓰기 (변경 사항 저장)
            .build();
}

// --- 각 컴포넌트 정의 (간소화버젼쓰) ---

@Bean
public ItemReader<User> inactiveUserReader() {
    // 1년 이상 로그인 안 한 유저 조회 쿼리 등...
    return new JdbcCursorItemReaderBuilder<User>()...build();
}

@Bean
public ItemProcessor<User, User> inactiveUserProcessor() {
    return user -> {
        // 읽어온 유저 데이터를 '휴면'으로 상태 변경
        user.setStatus(UserStatus.INACTIVE);
        return user;
    };
}

@Bean
public ItemWriter<User> inactiveUserWriter() {
    // 변경된 유저 리스트를 한 번에 DB 업데이트 (Chunk 단위 실행)
    return users -> {
        userRepository.saveAll(users); 
    };
}

 


한 눈에 비교하기

구분 Tasklet (태스크릿) Chunk (청크)
주 목 단순 작업 (알림, 삭제 등) 대용량 데이터 처리 (ETL)
처리 단위 Step 전체가 하나의 트랜잭션 Chunk Size만큼 쪼개서 트랜잭션
구성 요소 Tasklet 구현체 하나 Reader → Processor → Writer
메모리 한 번에 처리 (주의 필요) 일정량만 로드 (효율적)

 

 

"배치는 무조건 Chunk지!"라고 생각하기 쉽지만, 데이터 입출력이 없는 단순 작업에 Chunk를 쓰는 건 과유불급입니다. 상황에 맞는 칼을 뽑아 드는 것이 진정한 엔지니어겠죠?

 

"Chunk 지향 처리에서 Processor는 필수가 아니라 선택입니다"