๋ฐฐ์น˜ ์ฒ˜๋ฆฌ vs ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ

๋ฐฐ์น˜ ์ฒ˜๋ฆฌ vs ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ. ์Œ“์•„์„œ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ• ๊นŒ, ๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ ์ฒ˜๋ฆฌํ• ๊นŒ. ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์„ Spring Batch์™€ Kafka๋ผ๋Š” ๋Œ€ํ‘œ ๋„๊ตฌ๋กœ ์‚ดํŽด๋ณด๊ณ , ์–ธ์ œ ๋ฌด์—‡์„ ์จ์•ผ ํ•˜๋Š”์ง€ ์‹ค์ œ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์ •๋ฆฌํ•œ๋‹ค.


๋“ค์–ด๊ฐ€๋ฉฐ

๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐˆ๋ž˜๋‹ค. ํ•˜๋‚˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์•„๋’€๋‹ค๊ฐ€ ์ •ํ•ด์ง„ ์‹œ์ ์— ํ•œ๊บผ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฐ์น˜(Batch), ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ ํ˜๋ ค๋ณด๋‚ด๋ฉฐ ์ฒ˜๋ฆฌํ•˜๋Š” ์ŠคํŠธ๋ฆผ(Stream)์ด๋‹ค.

"๋งค์ผ ์ƒˆ๋ฒฝ 2์‹œ์— ์–ด์ œ ๋งค์ถœ์„ ์ง‘๊ณ„ํ•œ๋‹ค"๋ฉด ๋ฐฐ์น˜, "๊ฒฐ์ œ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์ˆœ๊ฐ„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ด์ƒ ๊ฑฐ๋ž˜๋ฅผ ํƒ์ง€ํ•œ๋‹ค"๋ฉด ์ŠคํŠธ๋ฆผ์ด๋‹ค. ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ผ๋„ ์–ธ์ œ ์ฒ˜๋ฆฌํ•˜๋А๋ƒ์— ๋”ฐ๋ผ ์ ‘๊ทผ์ด ์™„์ „ํžˆ ๋‹ฌ๋ผ์ง„๋‹ค.

๋ฐฐ์น˜๋Š” "์Œ“์•„์„œ ํ•œ ๋ฒˆ์—", ์ŠคํŠธ๋ฆผ์€ "๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ". ์ด ํƒ€์ด๋ฐ์˜ ์ฐจ์ด๊ฐ€ ๋„๊ตฌ ์„ ํƒ์„ ๊ฐ€๋ฅธ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ๋‘ ๋ฐฉ์‹์˜ ๊ฐœ๋…์„ ์žก๊ณ , ๊ฐ๊ฐ์˜ ๋Œ€ํ‘œ ๋„๊ตฌ์ธ Spring Batch(๋ฐฐ์น˜)์™€ Kafka(์ŠคํŠธ๋ฆผ)๋ฅผ ์‹ค์ œ ์ฝ”๋“œ๋กœ ์‚ดํŽด๋ณธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ธ์ œ ๋ฌด์—‡์„ ์จ์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•œ๋‹ค.


๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋ž€

๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ผ์ • ๊ธฐ๊ฐ„ ๋ชจ์•˜๋‹ค๊ฐ€, ์ •ํ•ด์ง„ ์‹œ์ ์— ๋ฌถ์Œ(batch)์œผ๋กœ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ „ํ†ต์ ์ด๊ณ  ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด๋‹ค.

ํŠน์ง•์€ ์ด๋ ‡๋‹ค.

  • ์ •ํ•ด์ง„ ์‹œ์ ์— ์‹คํ–‰๋œ๋‹ค (๋งค์ผ ์ƒˆ๋ฒฝ, ๋งค์‹œ ์ •๊ฐ ๋“ฑ)
  • ํ•œ ๋ฒˆ์— ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค
  • ์‹ค์‹œ๊ฐ„์ผ ํ•„์š”๊ฐ€ ์—†๋‹ค (๋ช‡ ์‹œ๊ฐ„ ๋Šฆ์–ด๋„ ๋˜๋Š” ์ž‘์—…)
  • ์ฒ˜๋ฆฌ๋Ÿ‰(throughput)์ด ์ค‘์š”ํ•˜๊ณ , ์ง€์—ฐ์‹œ๊ฐ„(latency)์€ ๋œ ์ค‘์š”ํ•˜๋‹ค

๋Œ€ํ‘œ์ ์ธ ์˜ˆ๊ฐ€ ์ •์‚ฐ, ํ†ต๊ณ„ ์ง‘๊ณ„, ๋Œ€๋Ÿ‰ ๋ฉ”์ผ ๋ฐœ์†ก, ๋ฐ์ดํ„ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด๋‹ค. "์–ด์ œ ํ•˜๋ฃจ์น˜๋ฅผ ์˜ค๋Š˜ ์ƒˆ๋ฒฝ์— ์ •๋ฆฌ"ํ•˜๋Š” ์‹์˜ ์ž‘์—…์ด ์ „ํ˜•์ ์ด๋‹ค.


Spring Batch — ๋ฐฐ์น˜์˜ ๋Œ€ํ‘œ ๋„๊ตฌ

์ž๋ฐ” ์ง„์˜์—์„œ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ์˜ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€์€ Spring Batch๋‹ค. "์š”์ฆ˜๋„ ์“ฐ๋‚˜?" ์‹ถ์ง€๋งŒ, ๊ธˆ์œต·๋ณดํ—˜·์ •์‚ฐ์ฒ˜๋Ÿผ ๋Œ€๋Ÿ‰์˜ ์ •ํ˜• ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์˜์—ญ์—์„œ๋Š” ์—ฌ์ „ํžˆ ํ˜„์—ญ์ด๋‹ค. ์ฒญํฌ ๋‹จ์œ„ ์ฒ˜๋ฆฌ, ์‹คํŒจ ์‹œ ์žฌ์‹œ์ž‘, skip/retry ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ง์ ‘ ๋งŒ๋“ค๋ฉด ๋”์ฐํ•œ๋ฐ, Spring Batch๊ฐ€ ๋‹ค ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•ต์‹ฌ ๊ตฌ์กฐ๋Š” Job → Step → (Reader-Processor-Writer) ๋‹ค.

Job (๋ฐฐ์น˜ ์ž‘์—… ์ „์ฒด)
 โ”” Step (ํ•˜๋‚˜์˜ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„)
    โ”œ ItemReader    : ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜จ๋‹ค (DB, ํŒŒ์ผ)
    โ”œ ItemProcessor : ํ•œ ๊ฑด์”ฉ ๊ฐ€๊ณตํ•œ๋‹ค
    โ”” ItemWriter    : ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•œ๋‹ค

ํšŒ์›๋“ค์˜ ์–ด์ œ ์ฃผ๋ฌธ์„ ์ง‘๊ณ„ํ•˜๋Š” ๋ฐฐ์น˜๋ฅผ ์˜ˆ๋กœ ๋ณด์ž.

@Configuration
public class OrderSummaryBatch {

    // 1. Reader — DB์—์„œ ์ฃผ๋ฌธ์„ ํ•œ ๊ฑด์”ฉ ์ฝ๋Š”๋‹ค (์ปค์„œ ๊ธฐ๋ฐ˜: ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ )
    @Bean
    public JdbcCursorItemReader<Order> reader(DataSource dataSource) {
        return new JdbcCursorItemReaderBuilder<Order>()
                .name("orderReader")
                .dataSource(dataSource)
                .sql("SELECT id, user_id, amount FROM orders " +
                     "WHERE created_at >= CURRENT_DATE - 1")
                .rowMapper((rs, n) -> new Order(
                        rs.getLong("id"),
                        rs.getLong("user_id"),
                        rs.getInt("amount")))
                .build();
    }

    // 2. Processor — ํ•œ ๊ฑด์”ฉ ๊ฐ€๊ณต (์˜ˆ: ์ง‘๊ณ„์šฉ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜)
    @Bean
    public ItemProcessor<Order, OrderSummary> processor() {
        return order -> new OrderSummary(order.userId(), order.amount());
    }

    // 3. Writer — ๊ฒฐ๊ณผ๋ฅผ ์ง‘๊ณ„ ํ…Œ์ด๋ธ”์— ์ €์žฅ
    @Bean
    public JdbcBatchItemWriter<OrderSummary> writer(DataSource dataSource) {
        return new JdbcBatchItemWriterBuilder<OrderSummary>()
                .dataSource(dataSource)
                .sql("INSERT INTO order_summary (user_id, total) " +
                     "VALUES (:userId, :total)")
                .beanMapped()
                .build();
    }

    // 4. Step — Reader-Processor-Writer๋ฅผ ๋ฌถ๊ณ , chunk(10)๋กœ ์ฒ˜๋ฆฌ
    @Bean
    public Step step(JobRepository repo, PlatformTransactionManager tm,
                     JdbcCursorItemReader<Order> reader,
                     ItemProcessor<Order, OrderSummary> processor,
                     JdbcBatchItemWriter<OrderSummary> writer) {
        return new StepBuilder("summaryStep", repo)
                .<Order, OrderSummary>chunk(10, tm)  // 10๊ฑด์”ฉ ๋ฌถ์–ด ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }

    // 5. Job — ์ „์ฒด ๋ฐฐ์น˜ ์ž‘์—…
    @Bean
    public Job orderSummaryJob(JobRepository repo, Step step) {
        return new JobBuilder("orderSummaryJob", repo)
                .start(step)
                .build();
    }
}

์—ฌ๊ธฐ์„œ chunk(10) ๊ฐ€ ํ•ต์‹ฌ์ด๋‹ค. 10๊ฑด์”ฉ ๋ฌถ์–ด์„œ ์ฝ๊ณ -๊ฐ€๊ณตํ•˜๊ณ -์“ฐ๊ณ ๋ฅผ ํ•œ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. 100๋งŒ ๊ฑด์„ ํ•œ ๋ฒˆ์— ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ  10๊ฑด์”ฉ ๋‚˜๋ˆ  ์ฒ˜๋ฆฌํ•˜๋‹ˆ, ๋Œ€์šฉ๋Ÿ‰์—๋„ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ„ฐ์ง€์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ค‘๊ฐ„์— ์‹คํŒจํ•˜๋ฉด ๊ทธ ์ง€์ ๋ถ€ํ„ฐ ์žฌ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒŒ ์ง์ ‘ ์งœ๋ฉด ๊ณ ํ†ต์Šค๋Ÿฌ์šด, Spring Batch์˜ ๊ฐ€์น˜๋‹ค.

๋ณดํ†ต ์ด Job์„ ์Šค์ผ€์ค„๋Ÿฌ(@Scheduled๋‚˜ Quartz)๋กœ ๋งค์ผ ์ƒˆ๋ฒฝ์— ๋Œ๋ฆฐ๋‹ค.


์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ๋ž€

์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ๋Š” ์ •๋ฐ˜๋Œ€๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์œผ์ง€ ์•Š๊ณ , ๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ ํ•˜๋‚˜์”ฉ(๋˜๋Š” ์ž‘์€ ๋ฌถ์Œ์œผ๋กœ) ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

ํŠน์ง•์€ ์ด๋ ‡๋‹ค.

  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ฆ‰์‹œ ์ฒ˜๋ฆฌํ•œ๋‹ค
  • ์ง€์—ฐ์‹œ๊ฐ„(latency) ์ด ์ค‘์š”ํ•˜๋‹ค (๋ฐ€๋ฆฌ์ดˆ~์ดˆ ๋‹จ์œ„ ๋ฐ˜์‘)
  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š์ž„์—†์ด ํ๋ฅธ๋‹ค (๋์ด ์ •ํ•ด์ง€์ง€ ์•Š์Œ)
  • ์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘์ด ํ•„์š”ํ•œ ์ž‘์—…์— ์ ํ•ฉํ•˜๋‹ค

๋Œ€ํ‘œ์ ์ธ ์˜ˆ๊ฐ€ ์‹ค์‹œ๊ฐ„ ์ด์ƒ ๊ฑฐ๋ž˜ ํƒ์ง€, ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ, ๋กœ๊ทธ ๋ชจ๋‹ˆํ„ฐ๋ง, ์‹ค์‹œ๊ฐ„ ์ถ”์ฒœ์ด๋‹ค. "์ง€๊ธˆ ์ด ์ˆœ๊ฐ„ ์ผ์–ด๋‚˜๋Š” ์ผ์— ์ฆ‰์‹œ ๋ฐ˜์‘"ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด๋‹ค.


Kafka — ์ŠคํŠธ๋ฆผ์˜ ๋Œ€ํ‘œ ๋„๊ตฌ

์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ์˜ ์ค‘์‹ฌ์—๋Š” Apache Kafka๊ฐ€ ์žˆ๋‹ค. ์ •ํ™•ํžˆ๋Š” Kafka๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅด๋Š” ํ†ต๋กœ(๋ฉ”์‹œ์ง€ ํ/์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆฌ๋ฐ ํ”Œ๋žซํผ) ์ด๊ณ , ๊ทธ ์œ„์—์„œ ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ๊ฐ€ ์ผ์–ด๋‚œ๋‹ค.

ํ•ต์‹ฌ ๊ฐœ๋…์€ ์…‹์ด๋‹ค.

๊ฐœ๋… ์—ญํ• 
Producer ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ์ชฝ (์ด๋ฒคํŠธ ๋ฐœํ–‰)
Topic ๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์ด๋Š” ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ†ต๋กœ
Consumer ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ชฝ (์ด๋ฒคํŠธ ๊ตฌ๋…)

์ƒ์‚ฐ์ž๊ฐ€ ํ† ํ”ฝ์— ์ด๋ฒคํŠธ๋ฅผ ๋˜์ง€๋ฉด, ์†Œ๋น„์ž๊ฐ€ ๊ทธ๊ฑธ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ฃผ๋ฌธ์ด ๋ฐœ์ƒํ•  ๋•Œ๋งˆ๋‹ค ์ด๋ฒคํŠธ๋ฅผ ํ˜๋ ค๋ณด๋‚ด๋Š” ์˜ˆ๋ฅผ ๋ณด์ž.

Producer — ์ด๋ฒคํŠธ ๋ฐœํ–‰

@Service
public class OrderEventProducer {

    private final KafkaTemplate<String, OrderEvent> kafkaTemplate;

    public OrderEventProducer(KafkaTemplate<String, OrderEvent> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    // ์ฃผ๋ฌธ์ด ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค 'orders' ํ† ํ”ฝ์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ํ˜๋ ค๋ณด๋‚ธ๋‹ค
    public void publish(Order order) {
        OrderEvent event = new OrderEvent(
                order.getId(), order.getUserId(), order.getAmount());
        kafkaTemplate.send("orders", event);
        // ๋ฐฐ์น˜์ฒ˜๋Ÿผ ๋ชจ์œผ์ง€ ์•Š๋Š”๋‹ค. ๋ฐœ์ƒ ์ฆ‰์‹œ ์ „์†ก.
    }
}

Consumer — ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ

@Service
public class FraudDetectionConsumer {

    // 'orders' ํ† ํ”ฝ์— ์ด๋ฒคํŠธ๊ฐ€ ๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ ํ˜ธ์ถœ๋œ๋‹ค
    @KafkaListener(topics = "orders", groupId = "fraud-detection")
    public void handle(OrderEvent event) {
        // ์‹ค์‹œ๊ฐ„ ์ด์ƒ ๊ฑฐ๋ž˜ ํƒ์ง€ — ๋“ค์–ด์˜ค์ž๋งˆ์ž ๊ฒ€์‚ฌ
        if (event.amount() > 10_000_000) {
            alertService.notify("๊ณ ์•ก ๊ฒฐ์ œ ๊ฐ์ง€: " + event.orderId());
        }
        // ์ƒˆ๋ฒฝ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ์ง€๊ธˆ ์ฆ‰์‹œ ๋ฐ˜์‘.
    }
}

๋ฐฐ์น˜ ์ฝ”๋“œ์™€ ๋น„๊ตํ•˜๋ฉด ์ฐจ์ด๊ฐ€ ๋ถ„๋ช…ํ•˜๋‹ค. Spring Batch๋Š” "์–ด์ œ์น˜๋ฅผ ๋ชจ์•„์„œ ์ƒˆ๋ฒฝ์— ํ•œ ๋ฒˆ์—" ์ฒ˜๋ฆฌํ–ˆ์ง€๋งŒ, Kafka๋Š” "์ฃผ๋ฌธ์ด ์ƒ๊ธฐ๋Š” ๋งค ์ˆœ๊ฐ„ ์ฆ‰์‹œ" ์ฒ˜๋ฆฌํ•œ๋‹ค. ๊ฐ™์€ ์ฃผ๋ฌธ ๋ฐ์ดํ„ฐ์ธ๋ฐ ์ฒ˜๋ฆฌ ํƒ€์ด๋ฐ์ด ์ •๋ฐ˜๋Œ€๋‹ค.

Kafka์˜ ๋˜ ๋‹ค๋ฅธ ๊ฐ•์ ์€ ํ•˜๋‚˜์˜ ํ† ํ”ฝ์„ ์—ฌ๋Ÿฌ ์†Œ๋น„์ž๊ฐ€ ๊ฐ์ž ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. orders ํ† ํ”ฝ ํ•˜๋‚˜๋ฅผ ์ด์ƒํƒ์ง€ ์†Œ๋น„์ž, ์•Œ๋ฆผ ์†Œ๋น„์ž, ํ†ต๊ณ„ ์†Œ๋น„์ž๊ฐ€ ๋™์‹œ์— ๋ฐ›์•„ ๊ฐ์ž ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜์˜ ํ† ๋Œ€๊ฐ€ ๋œ๋‹ค.


ํ•œ๋ˆˆ์— ๋น„๊ต

๋ฐฐ์น˜ VS ์ŠคํŠธ๋ฆผ

  ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ (Spring Batch) ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ (Kafka)
์ฒ˜๋ฆฌ ์‹œ์  ์ •ํ•ด์ง„ ์‹œ์ ์— ํ•œ ๋ฒˆ์— ๋ฐ์ดํ„ฐ ๋ฐœ์ƒ ์ฆ‰์‹œ
๋ฐ์ดํ„ฐ ๋ชจ์•„๋‘” ์œ ํ•œํ•œ ๋ฌถ์Œ ๋Š์ž„์—†์ด ํ๋ฅด๋Š” ๋ฐ์ดํ„ฐ
์ค‘์š” ์ง€ํ‘œ ์ฒ˜๋ฆฌ๋Ÿ‰(throughput) ์ง€์—ฐ์‹œ๊ฐ„(latency)
์ง€์—ฐ ํ—ˆ์šฉ๋จ (๋ช‡ ์‹œ๊ฐ„ OK) ์ตœ์†Œํ™” (๋ฐ€๋ฆฌ์ดˆ~์ดˆ)
๋Œ€ํ‘œ ์˜ˆ ์ •์‚ฐ, ํ†ต๊ณ„, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์‹ค์‹œ๊ฐ„ ํƒ์ง€, ์•Œ๋ฆผ, ๋ชจ๋‹ˆํ„ฐ๋ง
๋ณต์žก๋„ ์ƒ๋Œ€์ ์œผ๋กœ ๋‹จ์ˆœ ์ธํ”„๋ผ ์šด์˜ ๋ณต์žก

๊ทธ๋ž˜์„œ, ๋ฌด์—‡์„ ์จ์•ผ ํ•˜๋‚˜

์„ ํƒ ๊ธฐ์ค€์€ ๊ฒฐ๊ตญ "์–ผ๋งˆ๋‚˜ ๋นจ๋ฆฌ ๋ฐ˜์‘ํ•ด์•ผ ํ•˜๋Š”๊ฐ€" ๋‹ค.

๋ฐฐ์น˜๊ฐ€ ๋งž๋Š” ๊ฒฝ์šฐ

  • ์‹ค์‹œ๊ฐ„์ผ ํ•„์š”๊ฐ€ ์—†๋‹ค (์ผ/์‹œ๊ฐ„ ๋‹จ์œ„๋กœ ์ถฉ๋ถ„)
  • ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ, ์ •ํ™•ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค
  • ์ •์‚ฐ·ํ†ต๊ณ„·๋ฆฌํฌํŠธ์ฒ˜๋Ÿผ ์ •ํ•ด์ง„ ์ฃผ๊ธฐ์˜ ์ž‘์—…
  • ์‹คํŒจ ์‹œ ์žฌ์‹œ์ž‘·์ •ํ•ฉ์„ฑ์ด ์ค‘์š”ํ•˜๋‹ค → Spring Batch

์ŠคํŠธ๋ฆผ์ด ๋งž๋Š” ๊ฒฝ์šฐ

  • ์ฆ‰๊ฐ์ ์ธ ๋ฐ˜์‘์ด ํ•„์š”ํ•˜๋‹ค (์ด์ƒ ํƒ์ง€, ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ)
  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋Š์ž„์—†์ด ๋ฐœ์ƒํ•œ๋‹ค
  • ์—ฌ๋Ÿฌ ์‹œ์Šคํ…œ์ด ๊ฐ™์€ ์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•ด์•ผ ํ•œ๋‹ค → Kafka

๊ทธ๋ฆฌ๊ณ  ์ค‘์š”ํ•œ ์  — ๋‘˜์€ ์–‘์žํƒ์ผ์ด ์•„๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ๋Š” ์ž์ฃผ ํ•จ๊ป˜ ์“ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Kafka๋กœ ์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ, ๋™์‹œ์— ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์Œ“์•„๋’€๋‹ค๊ฐ€ ์ƒˆ๋ฒฝ ๋ฐฐ์น˜๋กœ ์ผ๋ณ„ ์ง‘๊ณ„๋ฅผ ๋Œ๋ฆฐ๋‹ค. "์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘์€ ์ŠคํŠธ๋ฆผ, ๋Œ€๋Ÿ‰ ์ง‘๊ณ„๋Š” ๋ฐฐ์น˜"๋กœ ์—ญํ• ์„ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด๋‹ค.

์ŠคํŠธ๋ฆผ์ด ๋ฐฐ์น˜๋ฅผ ์™„์ „ํžˆ ๋Œ€์ฒดํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋‹ค. ๋น ๋ฅธ ๋ฐ˜์‘์ด ํ•„์š”ํ•œ ๊ณณ์—” ์ŠคํŠธ๋ฆผ, ์ •ํ™•ํ•œ ๋Œ€๋Ÿ‰ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์—” ๋ฐฐ์น˜. ๋‘˜์€ ๊ณต์กดํ•œ๋‹ค.


๋งˆ์น˜๋ฉฐ

๋ฐฐ์น˜์™€ ์ŠคํŠธ๋ฆผ์€ "๋ฐ์ดํ„ฐ๋ฅผ ์–ธ์ œ ์ฒ˜๋ฆฌํ•˜๋А๋ƒ"์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ๋‹ต์ด๋‹ค. ์Œ“์•„์„œ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฐ์น˜(Spring Batch)๋Š” ์ •์‚ฐ·์ง‘๊ณ„์ฒ˜๋Ÿผ ์ •ํ™•์„ฑ๊ณผ ์ฒ˜๋ฆฌ๋Ÿ‰์ด ์ค‘์š”ํ•œ ๊ณณ์—์„œ ์—ฌ์ „ํžˆ ๊ฐ•๋ ฅํ•˜๊ณ , ๋“ค์–ด์˜ค๋Š” ์ฆ‰์‹œ ์ฒ˜๋ฆฌํ•˜๋Š” ์ŠคํŠธ๋ฆผ(Kafka)์€ ์‹ค์‹œ๊ฐ„ ๋ฐ˜์‘์ด ํ•„์š”ํ•œ ๊ณณ์—์„œ ๋น›๋‚œ๋‹ค.

"์š”์ฆ˜์€ ๋‹ค ์‹ค์‹œ๊ฐ„ ์•„๋‹ˆ์•ผ?"๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ์‰ฝ์ง€๋งŒ, ํ˜„์‹ค์€ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค. ์ƒˆ๋ฒฝ์— ํ•œ ๋ฒˆ ๋Œ๋ฆฌ๋ฉด ๋˜๋Š” ์ผ์„ ๊ตณ์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋งŒ๋“ค๋ฉด ์ธํ”„๋ผ๋งŒ ๋ณต์žกํ•ด์ง„๋‹ค. ๋ฐ˜๋Œ€๋กœ ์ฆ‰๊ฐ ๋ฐ˜์‘ํ•ด์•ผ ํ•  ์ผ์„ ๋ฐฐ์น˜๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋„ˆ๋ฌด ๋Šฆ๋Š”๋‹ค. ํ•ต์‹ฌ์€ ํ’€๋ ค๋Š” ๋ฌธ์ œ๊ฐ€ ์‹ค์‹œ๊ฐ„์„ ์š”๊ตฌํ•˜๋Š”์ง€ ๋จผ์ € ๋ฌป๋Š” ๊ฒƒ์ด๋‹ค.

์ข‹์€ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” ๋‘˜ ๋‹ค ์ดํ•ดํ•˜๊ณ , ๋ฌธ์ œ์— ๋งž๊ฒŒ ๊ณ ๋ฅด๊ฑฐ๋‚˜ ์กฐํ•ฉํ•œ๋‹ค. ๋ฐฐ์น˜๋ƒ ์ŠคํŠธ๋ฆผ์ด๋ƒ๊ฐ€ ์•„๋‹ˆ๋ผ, ์–ด๋””์— ๋ฌด์—‡์„ ์“ธ์ง€๊ฐ€ ์ง„์งœ ์‹ค๋ ฅ์ด๋‹ค.


์ฐธ๊ณ  ์ถœ์ฒ˜