# Spring Batch 대용량 처리 프로젝트 Spring Boot + Spring Batch + Quartz를 사용한 대용량 데이터 처리 배치 프로젝트입니다. ## 기술 스택 - **Java**: OpenJDK 1.8 - **Framework**: Spring Boot 2.3.12 - **Batch**: Spring Batch - **Scheduler**: Quartz (Clustering 지원) - **Database**: MariaDB - **ORM**: MyBatis - **Build Tool**: Gradle ## 주요 기능 ### 1. 대용량 데이터 처리 - Chunk 기반 처리 (5,000건씩) - JdbcPagingItemReader를 사용한 효율적인 데이터 읽기 - MyBatis Batch Insert를 통한 성능 최적화 ### 2. 배치 처리 흐름 ``` 파일/DB 읽기 → 데이터 처리 → API 호출 → 결과 저장 ``` ### 3. 실패 대응 - Skip 처리: 최대 100건까지 오류 허용 - Retry 처리: 실패 시 최대 3회 재시도 - 실패 로그 자동 저장 - JobExecutionListener를 통한 모니터링 ### 4. 스케줄링 관리 - Quartz Scheduler 사용 - Cron 표현식을 통한 유연한 스케줄링 - 기본 설정: 매일 새벽 2시 실행 ### 5. 서버 다중화 지원 - Quartz Clustering 설정 - DB 기반 Job 동기화 - 중복 실행 방지 (@DisallowConcurrentExecution) ### 6. Transaction 관리 - Spring Batch의 Chunk 단위 트랜잭션 - MyBatis 트랜잭션 통합 ## 프로젝트 구조 ``` src/main/java/com/example/batch/ ├── BatchApplication.java # Main 클래스 ├── config/ │ ├── BatchConfig.java # Spring Batch 설정 │ └── MyBatisConfig.java # MyBatis 설정 ├── domain/ │ ├── Customer.java # 고객 도메인 │ ├── CustomerProcessed.java # 처리된 고객 데이터 │ └── BatchLog.java # 배치 로그 ├── job/ │ ├── CustomerBatchJobConfig.java # 배치 Job 설정 │ └── CustomerJobExecutionListener.java # Job 실행 리스너 ├── mapper/ │ ├── CustomerMapper.java # 고객 Mapper │ └── BatchLogMapper.java # 로그 Mapper └── scheduler/ ├── BatchScheduler.java # Quartz 스케줄러 설정 └── CustomerBatchQuartzJob.java # Quartz Job src/main/resources/ ├── application.yml # 애플리케이션 설정 ├── db/ │ └── schema.sql # DB 스키마 └── mapper/ ├── CustomerMapper.xml # 고객 쿼리 └── BatchLogMapper.xml # 로그 쿼리 ``` ## 폐쇄망 환경 지원 (Nexus) 이 프로젝트는 폐쇄망 환경에서 내부 Nexus Repository Manager를 사용할 수 있도록 설정되어 있습니다. ### 빠른 시작 폐쇄망에서 사용하려면 다음 파일들을 참고하세요: - **QUICK_START_NEXUS.md**: Nexus 빠른 설정 가이드 - **NEXUS_SETUP.md**: Nexus 상세 설정 가이드 - **NEXUS_LOCAL_SETUP.md**: Docker로 로컬 Nexus 테스트 환경 구성 ### Nexus 설정 방법 1. `gradle.properties.example`을 복사하여 `gradle.properties` 생성 2. Nexus 정보 입력: ```properties nexusUrl=http://nexus.your-company.com:8081 nexusUsername=your-username nexusPassword=your-password ``` 3. `build.gradle`에서 Nexus 주석 해제 및 mavenCentral() 주석 처리 4. 빌드: `gradlew.bat clean build` 자세한 내용은 **NEXUS_SETUP.md**를 참고하세요. ## 설치 및 실행 ### 1. 데이터베이스 설정 MariaDB에 데이터베이스 및 사용자를 생성합니다: ```sql CREATE DATABASE batch_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'batch_user'@'%' IDENTIFIED BY 'batch_password'; GRANT ALL PRIVILEGES ON batch_db.* TO 'batch_user'@'%'; FLUSH PRIVILEGES; ``` ### 2. 스키마 생성 `src/main/resources/db/schema.sql` 파일을 실행하여 필요한 테이블을 생성합니다: ```bash mysql -u batch_user -p batch_db < src/main/resources/db/schema.sql ``` 또는 MySQL 클라이언트에서: ```sql USE batch_db; SOURCE D:/workspace/springbatch-test/src/main/resources/db/schema.sql; ``` ### 3. application.yml 수정 `src/main/resources/application.yml`에서 데이터베이스 연결 정보를 수정합니다: ```yaml spring: datasource: url: jdbc:mariadb://localhost:3306/batch_db username: batch_user password: batch_password ``` ### 4. 빌드 및 실행 ```bash # Gradle 빌드 ./gradlew clean build # 애플리케이션 실행 ./gradlew bootRun # 또는 JAR 파일 실행 java -jar build/libs/springbatch-test-1.0.0.jar ``` Windows에서는: ```cmd gradlew.bat clean build gradlew.bat bootRun ``` ## 배치 Job 실행 방법 ### 1. 스케줄러에 의한 자동 실행 - 기본 설정: 매일 새벽 2시 실행 - Quartz Trigger 설정 변경: `BatchScheduler.java` ### 2. 수동 실행 (테스트용) REST API를 추가하여 수동 실행할 수 있습니다: ```java @RestController @RequestMapping("/api/batch") public class BatchController { @Autowired private JobLauncher jobLauncher; @Autowired @Qualifier("customerProcessingJob") private Job customerProcessingJob; @PostMapping("/run") public String runBatch() throws Exception { JobParameters jobParameters = new JobParametersBuilder() .addLong("timestamp", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(customerProcessingJob, jobParameters); return "Batch job started"; } } ``` ## 설정 커스터마이징 ### 1. Chunk Size 변경 `CustomerBatchJobConfig.java`: ```java private static final int CHUNK_SIZE = 5000; // 원하는 크기로 변경 private static final int PAGE_SIZE = 5000; // 원하는 크기로 변경 ``` ### 2. 스케줄 변경 `BatchScheduler.java`: ```java // Cron 표현식 예시: // "0 0 2 * * ?" - 매일 02:00 // "0 0 */6 * * ?" - 6시간마다 // "0 0/30 * * * ?" - 30분마다 CronScheduleBuilder.cronSchedule("0 0 2 * * ?") ``` ### 3. Skip/Retry 정책 변경 `CustomerBatchJobConfig.java`: ```java .faultTolerant() .skip(Exception.class) .skipLimit(100) // Skip 허용 횟수 .retryLimit(3) // Retry 횟수 .retry(Exception.class) ``` ### 4. API 엔드포인트 변경 `CustomerBatchJobConfig.java`의 `callExternalApi()` 메서드: ```java WebClient webClient = WebClient.builder() .baseUrl("https://your-api-endpoint.com") // 실제 API URL로 변경 .build(); ``` ## 모니터링 ### 1. 배치 실행 로그 확인 ```sql -- 최근 배치 실행 내역 SELECT * FROM TB_BATCH_LOG ORDER BY CREATED_AT DESC LIMIT 10; -- 실패한 배치 조회 SELECT * FROM TB_BATCH_LOG WHERE STATUS = 'FAILED'; ``` ### 2. Spring Batch 메타데이터 확인 ```sql -- Job 실행 내역 SELECT * FROM BATCH_JOB_EXECUTION ORDER BY CREATE_TIME DESC; -- Step 실행 상세 SELECT * FROM BATCH_STEP_EXECUTION ORDER BY START_TIME DESC; ``` ### 3. Quartz 스케줄러 상태 확인 ```sql -- 등록된 Job 확인 SELECT * FROM QRTZ_JOB_DETAILS; -- Trigger 상태 확인 SELECT * FROM QRTZ_TRIGGERS; -- 클러스터링 상태 확인 SELECT * FROM QRTZ_SCHEDULER_STATE; ``` ## 성능 튜닝 가이드 ### 1. 대용량 데이터 처리 최적화 ```yaml # application.yml batch: chunk-size: 5000 # 한 번에 처리할 레코드 수 page-size: 5000 # DB에서 읽어올 레코드 수 max-thread-pool-size: 5 # 병렬 처리 스레드 수 ``` ### 2. DB Connection Pool 조정 ```yaml spring: datasource: hikari: maximum-pool-size: 10 minimum-idle: 5 ``` ### 3. MyBatis Batch Insert `CustomerMapper.xml`의 `insertProcessedCustomerBatch`를 사용하면 성능 향상 ## 다중 서버 운영 ### Quartz Clustering 설정 1. 모든 서버가 같은 데이터베이스를 바라보도록 설정 2. `application.yml`에서 클러스터링 활성화 (기본 설정됨) 3. 각 서버는 자동으로 인스턴스 ID를 할당받음 4. 한 서버에서만 Job이 실행되며, 장애 시 다른 서버가 인계받음 ## 문제 해결 ### 1. 배치가 실행되지 않을 때 - Quartz 테이블이 생성되었는지 확인 - `QRTZ_SCHEDULER_STATE` 테이블에서 스케줄러 상태 확인 - 로그에서 에러 메시지 확인 ### 2. 중복 실행이 발생할 때 - Quartz 클러스터링이 올바르게 설정되었는지 확인 - 모든 서버가 같은 DB를 사용하는지 확인 - `@DisallowConcurrentExecution` 어노테이션 확인 ### 3. 데이터베이스 연결 오류 - MariaDB가 실행 중인지 확인 - 방화벽 설정 확인 - 연결 정보(URL, 사용자명, 비밀번호) 확인 ## 라이선스 MIT License