Spring Batch๋ฅผ ํ์ฉํ ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
๐น ๊ฐ์
๋๋์ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๊ฒ์ ๋ฐฑ์๋ ๊ฐ๋ฐ์์ ์ค์ํ ๊ณผ์ ์ค ํ๋์ ๋๋ค.
Spring Batch๋ ์ด๋ฌํ ์๊ตฌ๋ฅผ ์ถฉ์กฑ์ํค๊ธฐ ์ํด ์ค๊ณ๋ ํ๋ ์์ํฌ๋ก, ๋ฐฐ์น ์์ ์ ์์ ์ ์ด๊ณ ํ์ฅ ๊ฐ๋ฅํ๊ฒ ์คํํ ์ ์๋๋ก ๋์์ค๋๋ค.
๋ณธ ํฌ์คํ ์์๋ Spring Batch์ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ์ค์ ์์ , ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ๊น์ง ์์ธํ ๋ค๋ค๋ณด๊ฒ ์ต๋๋ค.
๐น Spring Batch๋?
Spring Batch๋ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ์ผ์ ํ ์ฃผ๊ธฐ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ ์ต์ ํ๋ ํ๋ ์์ํฌ์ ๋๋ค. ์ฃผ๋ก ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ฌ์ฉ๋ฉ๋๋ค.
- ์ ๊ธฐ์ ์ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ: ์๋ฅผ ๋ค์ด, ๋งค์ผ ์๋ฒฝ ํน์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๋ ๊ฒฝ์ฐ
- ETL(Extract, Transform, Load) ์์ : ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ๋ณํ ํ ์ ์ฅํ๋ ๊ณผ์
- ๋๋์ ํธ๋์ญ์ ์ฒ๋ฆฌ: ๊ธ์ต, ๋ฌผ๋ฅ ์์คํ ๋ฑ์์ ๋๋์ ๋ฐ์ดํฐ๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌํ ๋
โ Spring Batch ์ฃผ์ ํน์ง
- ์ฒญํฌ(Chunk) ๊ธฐ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ: ๋ฐ์ดํฐ๋ฅผ ์ผ์ ๋จ์(์ฒญํฌ)๋ก ๋๋์ด ์ฒ๋ฆฌํ์ฌ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ์ ๊ทน๋ํ
- ํธ๋์ญ์ ๊ด๋ฆฌ: ์ฒ๋ฆฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ๋กค๋ฐฑ ์ง์
- ์ฌ์์ ๊ฐ๋ฅ์ฑ: ์คํจํ ๋ฐฐ์น ์์ ์ ์ค๋จ๋ ์ง์ ๋ถํฐ ๋ค์ ์คํ ๊ฐ๋ฅ
- ๋ณ๋ ฌ ์ฒ๋ฆฌ ์ง์: ๋ฉํฐ ์ค๋ ๋, ํํฐ์ ๋(Partitioning) ๋ฑ ๊ณ ์ฑ๋ฅ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ๊ธฐ๋ฅ ์ ๊ณต
๐น Spring Batch ์ํคํ ์ฒ ๋ฐ ์ฃผ์ ์ปดํฌ๋ํธ
Spring Batch๋ Job์ ์ค์ฌ์ผ๋ก ๋์ํ๋ฉฐ, ๊ทธ ๋ด๋ถ์์ Step์ ํตํด ์์ ์ด ์ํ๋ฉ๋๋ค. ์ฃผ์ ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Job: ๋ฐฐ์น ์์ ์ ์คํ ๋จ์
- Step: Job ๋ด๋ถ์์ ๊ฐ๋ณ์ ์ผ๋ก ์คํ๋๋ ๋จ์
- ItemReader: ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ์ญํ (์: DB, CSV, API ๋ฑ์์ ๋ฐ์ดํฐ ๋ก๋)
- ItemProcessor: ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๋ ์ญํ (์: ๋ณํ, ํํฐ๋ง ๋ฑ)
- ItemWriter: ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ญํ (์: DB, ํ์ผ ๋ฑ)
๐น ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ฑ๋ฅ์ ๊ทน๋ํํ๋ ๋ฐฉ๋ฒ์ ์์๋ด ๋๋ค.
โ 1. ์ฒญํฌ ๊ธฐ๋ฐ ์ฒ๋ฆฌ (Chunk-Oriented Processing)
- ๋ฐ์ดํฐ๋ฅผ ์ผ์ ํฌ๊ธฐ๋ก ๋๋์ด ํ ๋ฒ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์
- ์ฒญํฌ ๋จ์๋ก ํธ๋์ญ์ ์ด ์ ์ฉ๋๋ฏ๋ก, ์ฅ์ ๋ฐ์ ์ ์ผ๋ถ ๋ฐ์ดํฐ๋ง ๋กค๋ฐฑ ๊ฐ๋ฅ
@Bean
public Step chunkStep() {
return stepBuilderFactory.get("chunkStep")
.<InputData, ProcessedData>chunk(1000) // ํ ๋ฒ์ 1000๊ฐ์ฉ ์ฒ๋ฆฌ
.reader(itemReader())
.processor(itemProcessor())
.writer(itemWriter())
.build();
}
โ 2. Cursor ๊ธฐ๋ฐ vs ํ์ด์ง ๊ธฐ๋ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- Cursor ๊ธฐ๋ฐ: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค์๋ฅผ ์ด์ฉํด ๋ฐ์ดํฐ๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฝ์ → ๋ฉ๋ชจ๋ฆฌ ์ ์ฝ ๊ฐ๋ฅ
- ํ์ด์ง ๊ธฐ๋ฐ: ๋ฐ์ดํฐ๋ฅผ ํ์ด์ง ๋จ์๋ก ๊ฐ์ ธ์ด → ๋๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ ์ฑ๋ฅ ์ด์ ์ด ์์
โ 3. ๋ฉํฐ ์ค๋ ๋ & ๋ณ๋ ฌ ์ฒ๋ฆฌ
- ๋ฉํฐ ์ค๋ ๋ ์คํ : Step์ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๋ก ์คํํ์ฌ ์ฑ๋ฅ ํฅ์
- Partitioning: ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ๊ฐ์ ์ฒญํฌ๋ก ๋๋์ด ๋ถ์ฐ ์ฒ๋ฆฌ
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.initialize();
return executor;
}
๐น Spring Batch ์ค์ ์์ : CSV → DB ์ ์ฅ
๋ค์์ CSV ํ์ผ์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ , ๋ณํํ ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ์์ ์ ๋๋ค.
โ 1. ItemReader (CSV ํ์ผ ์ฝ๊ธฐ)
@Bean
public FlatFileItemReader<MyData> itemReader() {
return new FlatFileItemReaderBuilder<MyData>()
.name("csvReader")
.resource(new ClassPathResource("data.csv"))
.delimited()
.names("id", "name", "age")
.targetType(MyData.class)
.build();
}
โ 2. ItemProcessor (๋ฐ์ดํฐ ๋ณํ)
@Bean
public ItemProcessor<MyData, MyData> itemProcessor() {
return item -> {
item.setName(item.getName().toUpperCase());
return item;
};
}
โ 3. ItemWriter (DB ์ ์ฅ)
@Bean
public JdbcBatchItemWriter<MyData> itemWriter(DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<MyData>()
.dataSource(dataSource)
.sql("INSERT INTO my_table (id, name, age) VALUES (:id, :name, :age)")
.beanMapped()
.build();
}
๐น Spring Boot์์ Batch ์คํ ๋ฐ ๋ฐฐํฌ
- CommandLineRunner๋ฅผ ์ฌ์ฉํ ์คํ
- Spring Scheduler์ ์ฐ๋ํ์ฌ ์ฃผ๊ธฐ์ ์คํ
- ๋ฐฐํฌ ์ ๊ณ ๋ คํด์ผ ํ ์ (DB Lock, ๋ฐฐ์น ์คํ ์ด๋ ฅ ๊ด๋ฆฌ ๋ฑ)
๐น ๊ฒฐ๋ก
Spring Batch๋ฅผ ํ์ฉํ๋ฉด ๋์ฉ๋ ๋ฐ์ดํฐ๋ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.