Spring Batch를 다루다 보면 Step을 구성하는 두 가지 큰 갈래길, Tasklet과 Chunk를 마주하게 됩니다. "그냥 대충 쓰면 되는 거 아냐?"라고 생각했다면 오산! 이 둘은 용도가 명확히 다릅니다.
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는 필수가 아니라 선택입니다"
'SpringBoot' 카테고리의 다른 글
| 좋아요 구현, Exclusive Lock에 대해서 알아보자. (0) | 2026.04.22 |
|---|---|
| [Spring Batch] JobParameters와 Scope (0) | 2025.12.15 |
| Kafka를 이용해서 인기글 서비스를 어떻게 구현할 수 있을까? (0) | 2025.08.20 |
| 분산 이벤트 스트리밍 플랫폼, Kafka 아는척해보기 (3) | 2025.08.17 |
| Swagger를 사용해서 쉽게 api명세서를 만들어보자! (2) | 2024.12.01 |