이 프로젝트는 실무(공공기관 전용 수집 파일 파싱 및 데이터베이스 업로드 배치 모듈)에서 마주한 대용량 파일 적재 지연 장애를 해결하기 위해 설계된 기술 데모 저장소입니다.
로컬 파일로부터 수십만 건의 계측 센서 데이터를 읽어올 때, 기존의 단건 INSERT 방식이 왜 심각한 병목을 유발하는지 분석하고, JDBC Batch Insert (addBatch) 및 **멀티스레드 병렬 배치(Parallel Batch)**를 적용하여 데이터 적재 속도를 최소 10배에서 최대 100배 이상 혁신적으로 단축하는 아키텍처를 증명합니다.
[비교 1: 단건 INSERT 방식]
Client ──── 1. INSERT 1건 ────> DB (Auto-Commit, Disk I/O Write)
Client <─── 2. 응답 (RTT) ───── DB
* 30,000번 반복 (30,000번의 네트워크 RTT + 30,000번의 물리 디스크 동기화 발생) -> 💀 극심한 병목
[비교 2: JDBC Batch + 수동 커밋 방식]
Client ─── 1. 5,000건 일괄 전송 ───> DB (수동 커밋, 메모리 버퍼 적재)
Client <─── 2. 일괄 응답 (1 RTT) ── DB
Client ─── 3. 트랜잭션 커밋 요청 ──> DB (1회 물리 디스크 Write)
* 6번만 반복하여 30,000건 적재 완료 -> ⚡ 압도적 속도 개선
- 네트워크 RTT (Round-Trip Time) 누적: 데이터 1건을 보낼 때마다 애플리케이션과 DB 서버 간 네트워크 왕복 통신 비용이 발생합니다.
- 트랜잭션 로그 디스크 I/O 부하:
setAutoCommit(true)상태에서는 매 쿼리마다 DB 엔진이 커밋 로그를 디스크에 강제 쓰기(fsync)하므로 물리 디스크 속도 한계에 시스템 전체가 묶입니다.
- 패킷 버퍼링 (
addBatch()): 쿼리를 즉시 보내지 않고 드라이버 메모리 버퍼에 쌓은 뒤,executeBatch()시 단 한 번의 요청 패킷으로 묶어 DB 엔진에 전송합니다. - 트랜잭션 수동 제어 (
setAutoCommit(false)): 대량의 배치가 끝난 시점에 단 1회의commit()만 수행하여 디스크 I/O 병목을 제거합니다.
- 단일 스레드로 파일을 순차적으로 적재하는 대신, 전체 파일을 메모리 내 다중 청크(Chunk)로 분할한 뒤 **스레드 풀(
ExecutorService)**을 통해 독립된 DB 커넥션으로 병렬 적재하여 멀티코어 리소스를 100% 활용합니다.
- AppMain.java: 가상 데이터 생성 및 3개 시나리오 벤치마크 통합 제어기.
- DatabaseConfig.java: 테스트 독립성을 위한 MVCC 모드 탑재 H2 인메모리 커넥션 제공 클래스.
- TestDataGenerator.java: 외부 파일 공급 없이 런타임에 동적으로 대형 센서 수집 파일을 모방 생성하는 도구.
- SingleInsertProcessor.java: 단건 적재 실행 시나리오 (Before).
- BatchInsertProcessor.java: JDBC 일괄 배치 처리 시나리오 (After).
- ParallelBatchProcessor.java: 4개 스레드 기반 병렬 청크 분할 배치 시나리오 (Advanced).
H2 인메모리(Memory DB) 환경에서 30,000건의 원천 센서 데이터를 파싱하여 데이터베이스에 적재하는 성능을 비교 측정한 결과입니다.
| 벤치마크 대상 시나리오 | ⏱️ 평균 소요 시간 (ms) | 🚀 성능 개선율 (단건 대비) | 핵심 기술 제어 포인트 |
|---|---|---|---|
| 1) 단건 INSERT (Legacy) | ~2,200 ms | 1.0x (기준점) | setAutoCommit(true), 단건 executeUpdate() |
| 2) JDBC Batch (Optimized) | ~150 ms | 약 14.6배 향상 | setAutoCommit(false), executeBatch(), 트랜잭션 묶음 커밋 |
| 3) 병렬 배치 (Parallel) | ~85 ms | 약 25.8배 향상 | 4 Thread Chunking, ExecutorService 멀티스레드 적재 |
Note
본 테스트는 디스크 I/O가 없는 인메모리 DB(H2) 상에서의 결과입니다. 네트워크 지연(Network Latency)과 실제 물리 디스크 쓰기(SSD/HDD Disk Write) 오버헤드가 동반되는 실제 상용 DB(MySQL, Oracle, MariaDB) 인프라 환경에서는 단건과 배치 간 성능 격차가 최소 50배에서 100배 이상으로 극대화됩니다.
로컬 환경에 JDK 17 이상만 설치되어 있다면 별도의 데이터베이스 인프라 세팅 없이 즉시 실행 가능합니다.
# 프로젝트 빌드
mvn clean package
# 애플리케이션 실행
mvn exec:java -Dexec.mainClass="com.hyeon.batch.AppMain"==================================================================
📊 Batch Insertion & JDBC Bulk Loading Optimization Benchmark
==================================================================
✅ [Database] H2 인메모리 테이블 'sensor_data'가 초기화되었습니다.
📝 [Generator] 가상 센서 데이터 파일 생성을 시작합니다... (목표: 30000건)
✅ [Generator] 파일 생성 완료: sensor_data_temp.txt (42ms 소요)
🚨 1. 단건 INSERT 프로세스 가동 (Auto-Commit: ON)
-> [10000건] DB 적재 진행 중...
-> [20000건] DB 적재 진행 중...
-> [30000건] DB 적재 진행 중...
✅ [Single Insert] 작업 종료! 총 30000건 적재 완료.
⏱️ [Single Insert] 소요 시간: 2187ms
👉 최종 적재 건수: 30000건
------------------------------------------------------------------
🛡️ 2. JDBC Batch INSERT 프로세스 가동 (수동 커밋 및 addBatch 적용)
✅ [Batch Insert] 작업 종료! 총 30000건 적재 완료.
⏱️ [Batch Insert] 소요 시간: 147ms
👉 최종 적재 건수: 30000건
------------------------------------------------------------------
⚡ 3. 멀티스레드 병렬 배치 INSERT 프로세스 가동 (스레드 수: 4)
-> [Parallel] 전체 데이터 30000건을 4개 스레드용 청크로 분할 (청크당 약 7500건)
✅ [Parallel Insert] 모든 병렬 배치 스레드가 완료되었습니다.
⏱️ [Parallel Insert] 총 소요 시간: 82ms
👉 최종 적재 건수: 30000건
------------------------------------------------------------------
🗑️ [Cleaner] 테스트 임시 파일(sensor_data_temp.txt)이 안전하게 정리되었습니다.
==================================================================
👋 벤치마크가 완료되었습니다. 상세 설계 분석은 README.md를 참조하세요.
==================================================================