Spring Batch 정리

2026. 1. 16. 16:29·📚TIL

1️⃣ 배치(Batch)란?

일정 시간 동안 쌓인 대량의 데이터를 한 번에 처리하는 방식

  • 실시간 처리 ❌
  • 정합성·안정성·재시작이 핵심
  • 정산, 청구, 통계, 마이그레이션에 주로 사용

 

2️⃣ Spring Batch 프레임워크를 사용하는 이유

비즈니스 로직에만 집중하기 위해

 

Spring Batch가 대신 처리해 주는 것들:

  • 트랜잭션 관리
  • 실행 이력 기록
  • 실패 시 재시작
  • 중복 실행 방지
  • 대용량 처리 패턴(Chunk, Partition)

3️⃣ 실무에서의 Batch DB 구성

실무 원칙

  • Batch 메타데이터 DB
  • 운영 데이터 DB

👉 두 DB를 분리

이유

  • 운영 쿼리와 메타 쿼리 충돌 방지
  • 장애 전파 차단
  • 운영/백업 정책 분리

4️⃣ 배치에서 ‘기록’이 중요한 이유

배치의 핵심은:

중복 처리하거나 놓치는 데이터를 방지하는 것

이를 위해 모든 실행 상태를 기록한다.

  • 언제 실행했는지
  • 어디까지 처리했는지
  • 성공/실패 여부

👉 이 기록이 바로 메타데이터

 

🔹 1. BATCH_JOB_INSTANCE

📌 “이 Job은 무엇인가?”

Job + JobParameters 조합의 유일성을 관리하는 테이블

칼럼 설명

JOB_INSTANCE_ID Job Instance PK
JOB_NAME Job 이름
JOB_KEY JobParameters를 해시한 값

💡 실무 활용 포인트

  • 같은 파라미터로 Job 중복 실행 방지
  • “이 Job이 이미 실행된 적 있는가?” 판단 기준

🔹 2. BATCH_JOB_EXECUTION

📌 “이 Job은 언제, 어떻게 실행됐는가?”

Job 실행 한 번당 1 row

컬럼 설명
JOB_EXECUTION_ID Job 실행 PK
JOB_INSTANCE_ID 어떤 Job Instance인지
STATUS 실행 상태
START_TIME 시작 시간
END_TIME 종료 시간
EXIT_CODE 종료 코드
EXIT_MESSAGE 실패 사유 메시지

💡 실무에서 자주 보는 칼럼

  • STATUS
    • COMPLETED
    • FAILED
    • STOPPED
  • START_TIME / END_TIME
    • 배치 소요 시간 분석
  • EXIT_MESSAGE
    • 실패 원인 1차 확인

🔹 3. BATCH_JOB_EXECUTION_PARAMS

📌 “이 Job은 어떤 파라미터로 실행됐는가?”

Job 실행 시 전달한 파라미터 저장

컬럼 설명
JOB_EXECUTION_ID 어떤 실행인지
KEY_NAME 파라미터 이름
TYPE_CD 타입 (STRING, DATE 등)
STRING_VAL 값

💡 실무 활용 예

  • billingMonth=2026-01
  • requestDate=2026-01-31

👉 운영 중 특정 월/조건 배치 이력 조회할 때 핵심


🔹 4. BATCH_STEP_EXECUTION

📌 “Step 단위로 얼마나 처리했는가?”

성능·처리량 분석의 핵심 테이블

컬럼 설명
STEP_EXECUTION_ID Step 실행 PK
JOB_EXECUTION_ID 소속 Job
STEP_NAME Step 이름
STATUS Step 상태
READ_COUNT 읽은 건수
WRITE_COUNT 쓴 건수
FILTER_COUNT 필터링된 건수
COMMIT_COUNT 커밋 횟수
ROLLBACK_COUNT 롤백 횟수
START_TIME 시작
END_TIME 종료

⭐ 가장 중요한 칼럼 TOP 5

  1. READ_COUNT
  2. WRITE_COUNT
  3. FILTER_COUNT
  4. COMMIT_COUNT
  5. ROLLBACK_COUNT

👉 대용량 배치 튜닝·장애 분석의 핵심


🔹 5. BATCH_STEP_EXECUTION_CONTEXT

📌 “Step이 어디까지 처리했는가?”

Step 재시작을 위한 상태 저장소

컬럼 설명
STEP_EXECUTION_ID Step 실행
SHORT_CONTEXT 요약
SERIALIZED_CONTEXT 실제 Context

💡 실무 예시

  • 마지막 처리 ID
  • 마지막 페이지 번호
  • 마지막 커서 위치

👉 Cursor / Paging / Partition Step에서 매우 중요


🔹 6. BATCH_JOB_EXECUTION_CONTEXT

📌 “Job 전체에서 공유하는 상태”

Job 범위 ExecutionContext

컬럼 설명
JOB_EXECUTION_ID Job 실행
SERIALIZED_CONTEXT 공유 데이터

💡 활용 예

  • Step 간 공통 데이터 전달
  • 계산 결과 캐시

🔹 7. 시퀀스 테이블 (DB별)

  • BATCH_JOB_SEQ
  • BATCH_JOB_EXECUTION_SEQ
  • BATCH_STEP_EXECUTION_SEQ

👉 PK 생성용 (직접 다룰 일 거의 없음)


3️⃣ 배치 작업하면서 “특히 많이 쓰는 컬럼 요약”

📊 운영 모니터링용

목적 컬럼
성공/실패 여부 STATUS
실행 시간 START_TIME, END_TIME
실패 원인 EXIT_MESSAGE

 


 

📈 성능 분석용

목적 컬럼
처리량 READ_COUNT, WRITE_COUNT
필터링 FILTER_COUNT
트랜잭션 비용 COMMIT_COUNT
장애 ROLLBACK_COUNT

 


🔁 재시작/정합성

목적 컬럼
재시작 여부 STATUS, STEP_EXECUTION_CONTEXT
마지막 처리 위치 SERIALIZED_CONTEXT

 


5️⃣ Batch 기본 설정

batch.yml 예시

spring:
batch:
job:
enabled:false         # 애플리케이션 시작 시 자동 실행 방지
jdbc:
initialize-schema:always# 메타데이터 테이블 자동 생성

6️⃣ Batch 실행 방법

1. JobLauncher 직접 실행

jobLauncher.run(job, jobParameters);

2. API 호출

@PostMapping("/batch/run")
publicvoidrunBatch() {
    jobLauncher.run(job, jobParameters);
}

 


3. 스케줄러 실행

@Scheduled(cron = "0 0 2 * * *")
publicvoidrunBatch() {
    jobLauncher.run(job, jobParameters);
}

7️⃣ JobParameters란?

Job 실행을 구분하는 식별자

  • Job + JobParameters → JobInstance
  • 같은 Job이라도 파라미터가 다르면 다른 실행
JobParametersparams=newJobParametersBuilder()
    .addString("invMonth","202601")
    .toJobParameters();

👉 정산 배치에서 월별 실행 구분에 필수


8️⃣ Step 설정 핵심

Step 옵션

  • skip
  • → 특정 예외 발생 시 건너뜀
  • retry
  • → 예외 발생 시 재시도
  • Writer 롤백 제어
  • → Chunk 단위 트랜잭션 관리
  • StepListener
  • → Step 실행 전/후 훅
.stepBuilderFactory.get("step")
    .<A, B>chunk(1000)
    .faultTolerant()
    .skip(Exception.class)
    .skipLimit(10)
    .listener(stepListener)
    .build();

9️⃣ Job 설정 핵심

Step Flow

jobBuilderFactory.get("job")
    .start(step1)
    .next(step2)
    .build();

조건 분기

.start(step1)
.on("FAILED").end()
.from(step1).on("*").to(step2)

JobListener

.jobListener(jobListener)

 

👉 Job 실행 전/후 공통 로직 처리


🔟 JPA vs JDBC (Batch 관점)

JPA 문제점

  • Reader 성능 차이 ❌
  • Writer 성능 차이 큼

이유

  • IDENTITY 전략
  • Bulk Insert/Update 불가
  • SQL이 건별로 실행됨

JDBC 장점

  • Bulk 쿼리 가능
  • 대량 데이터 처리에 적합
  • Batch Writer 성능 우수
JdbcBatchItemWriter<Item> writer =
newJdbcBatchItemWriterBuilder<Item>()
        .sql("INSERT INTO table (...) VALUES (...)")
        .dataSource(dataSource)
        .build();

👉 Batch에서는 JDBC가 사실상 표준

 


Grid Size vs Chunk Size vs Page Size 

[ DB ]  --- (SELECT 1000개: PageSize) --->  [ 서버 Reader 메모리 ]
                                                     |
                                            (1개씩 꺼내기)
                                                     ↓
                                             [ ItemProcessor ]
                                                     ↓
                                            (1개씩 가공해서 넣기)
                                                     ↓
                                             [ Chunk Buffer ] (서버 메모리 List)
                                            (1,000개가 찰 때까지 반복)
                                                     ↓
[ DB ]  <--- (INSERT/UPDATE 1000개: Writer) --- [ 1,000개 완성! ]
[ DB ]  <--- (Commit: 트랜잭션 종료)

📌 요약하자면

  • PageSize: DB에서 서버로 데이터를 퍼오는 바가지 크기 (SELECT 쿼리 단위)
  • ChunkSize: 서버에서 처리를 다 끝내고 DB에 확정 짓는 단위 (Transaction/Write 단위)
  • Chunk Buffer: Writer에게 넘겨주기 전까지 가공된 데이터들을 잠시 담아두는 서버 안의 바구니

대부분의 실무에서는 바가지 크기(PageSize)와 확정 단위(ChunkSize)를 1000으로 똑같이 맞춰서 사용


Tasklet 방식 vs Chunk 방식

chunk방식

 

 

1. Tasklet 방식: "한 번에 하나의 작업"

Tasklet은 하나의 스텝(Step) 안에서 단일 로직을 처음부터 끝까지 수행하는 방식입니다.

  • 동작 원리: execute() 메서드 하나가 실행되고, RepeatStatus.FINISHED를 반환할 때까지 전체 로직이 돌아갑니다.
  • 주요 용도: 단순한 DB 업데이트 하나, 파일 삭제, 로그 출력, 시스템 명령어 실행 등 데이터 읽기/쓰기가 복잡하지 않은 작업에 적합합니다.
  • 특징: 트랜잭션 범위가 Tasklet 전체이며, 데이터가 작을 때 유리합니다.

2. Chunk 방식: "나눠서 반복 처리"

Chunk는 대량의 데이터를 일정 단위(Chunk)로 쪼개서 반복적으로 읽고, 가공하고, 쓰는 방식입니다.

  • 동작 원리: Reader(읽기) → Processor(처리) → Writer(쓰기)의 과정을 chunkSize만큼 반복합니다.
    • Reader: 데이터를 1개씩 읽어옵니다.
    • Processor: 읽어온 1개를 가공합니다.
    • Writer: chunkSize만큼 모인 리스트를 한 번에 DB에 저장합니다.
  • 주요 용도: 100만 건 같은 대용량 데이터 처리, 복잡한 비즈니스 로직이 들어가는 ETL 작업에 적합합니다.
  • 특징: chunkSize 단위로 트랜잭션이 커밋(Commit)되므로, 에러가 나도 해당 덩어리만 롤백하면 되어 안정적입니다.

Partitioning

하나의 Step을 여러 개의 “Worker Step”으로 쪼개 병렬로 실행하는 방식

 

 

1. 주요 구성 요소 (Components)

  • PartitionStep: 전체 파티셔닝 작업을 총괄하는 마스터(Master) 스텝입니다.
  • PartitionHandler: 파티션을 어떻게 다룰지(어떤 Worker 스텝으로 보낼지, 어떤 스레드 풀을 쓸지 등)를 결정합니다.
  • StepExecutionSplitter: 데이터를 어떤 범위로 나눌지 결정합니다. (예: 100만 건을 10만 건씩 10개로 분할)
  • Step (Worker Step): 실제로 비즈니스 로직(Read-Process-Write)을 수행하는 독립적인 작업 단위입니다.

2. 실행 흐름 (Execution Flow)

  1. execute(): PartitionStep이 실행을 시작합니다.
  2. handle(): PartitionStep은 PartitionHandler에게 파티션 처리를 요청합니다.
  3. split(): PartitionHandler는 StepExecutionSplitter를 호출하여 데이터를 여러 개의 실행 단위(StepExecution)로 쪼갭니다.
  4. execute() [repeat]: 분할된 각 실행 단위들에 대해 Worker Step들이 병렬적으로 실행됩니다. 그림에서 repeat은 여러 개의 스레드나 프로세스가 동시에 작업을 수행함을 의미합니다.
  5. join: 모든 Worker Step들의 작업이 끝날 때까지 기다린 후 결과를 취합합니다.
  6. aggregate: PartitionStep이 최종적으로 모든 파티션의 결과를 하나로 모아 정리하고 작업을 종료합니다.

@Bean
public Step step1Master() {
    return stepBuilderFactory.get("step1.master")
        .<String, String>partitioner("step1", partitioner())
        .step(step1())
        .gridSize(10)
        .taskExecutor(taskExecutor())
        .build();
}

 

 

'📚TIL' 카테고리의 다른 글
  • 종합 프로젝트 회고 (1/7~1/27)
  • Spring batch - 심화
  • SAA 정리 - 2
  • SAA 정리 - 1
개발하는 잔디
개발하는 잔디
  • 개발하는 잔디
    잔디의 개발일지
    개발하는 잔디
  • 전체
    오늘
    어제
    • 분류 전체보기 (22)
      • 📚TIL (22)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    유레카3기 백엔드반
    유레카백엔드3기
    유레카3기백엔드대면
    멀티캠퍼스부트캠프
    멀티캠퍼스 부트캠프
    Til
    til #springboot #코린이
    주간회고
    spring boot #백엔드
    유레카3기 백엔드
    유레카3기백엔드
    연말
    유레카3기 백엔드대면
    부트캠프 후기
    멀티캠퍼스IT부트캠프
    부트캠프후기
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
개발하는 잔디
Spring Batch 정리
상단으로

티스토리툴바