๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Kafka ํ”„๋กœ๋“€์„œ ๊ตฌํ˜„ํ•˜๊ธฐ: ๋ฉ”์‹œ์ง€ ์ „์†ก๋ถ€ํ„ฐ ์žฌ์‹œ๋„ ์ฒ˜๋ฆฌ๊นŒ์ง€

okrestart 2024. 10. 22.

 

Apache Kafka ๋Š” ๋Œ€๊ทœ๋ชจ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ๋งค์šฐ ์œ ์šฉํ•œ ๋ถ„์‚ฐ ๋ฉ”์‹œ์ง• ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค. ๊ทธ ์ค‘์—์„œ๋„ Kafka ํ”„๋กœ๋“€์„œ ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ Kafka ํ† ํ”ฝ ์œผ๋กœ ์ „์†กํ•˜๋Š” ํ•ต์‹ฌ ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” Kafka ํ”„๋กœ๋“€์„œ ์„œ๋น„์Šค ์ƒ์„ฑ , ๋ฉ”์‹œ์ง€ ์ „์†ก ๋ฐฉ๋ฒ• , Ack(์—ํฌ๋…ธ๋ ˆ์ง€๋จผํŠธ) ์ฒ˜๋ฆฌ , ์žฌ์‹œ๋„์™€ ๋ฒ„ํผ๋ง ์„ค์ • ๊นŒ์ง€ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์‹ค๋ฌด์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ๋”ฐ๋ผ ํ•˜๋ฉด์„œ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


 

 

1. Kafka ํ”„๋กœ๋“€์„œ ์„œ๋น„์Šค ์ƒ์„ฑ

Kafka ํ”„๋กœ๋“€์„œ ์„œ๋น„์Šค๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ ์—์„œ KafkaTemplate ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. KafkaTemplate ์€ ๋ฉ”์‹œ์ง€๋ฅผ Kafka๋กœ ์ „์†กํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@Service
public class KafkaProducerService {
    private static final Logger logger = LoggerFactory.getLogger(KafkaProducerService.class);
    private final KafkaTemplate<String, String> kafkaTemplate;

    @Autowired
    public KafkaProducerService(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendMessage(String message) {
        logger.info(String.format("#### -> Producing message -> %s", message));
        kafkaTemplate.send("my_topic", message);
    }
}

์„ค๋ช…:

  • KafkaTemplate ์„ ์ฃผ์ž…๋ฐ›์•„ ๋ฉ”์‹œ์ง€๋ฅผ Kafka๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  • sendMessage ๋ฉ”์„œ๋“œ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ my_topic ์œผ๋กœ ์ „์†กํ•˜๋ฉฐ, ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ์ „์†ก๋œ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


 

2. Kafka ํ† ํ”ฝ์œผ๋กœ ๋ฉ”์‹œ์ง€ ์ „์†กํ•˜๊ธฐ

Kafka์—์„œ๋Š” ํ”„๋กœ๋“€์„œ๋ฅผ ํ†ตํ•ด ํŠน์ • ํ† ํ”ฝ(topic) ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” KafkaTemplate.send() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ํ† ํ”ฝ์œผ๋กœ ์ „์†กํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๋ฉ”์‹œ์ง€ ์ „์†ก ์˜ˆ์ œ

@RestController
@RequestMapping("/api/kafka")
public class KafkaController {
    private final KafkaProducerService producerService;

    @Autowired
    public KafkaController(KafkaProducerService producerService) {
        this.producerService = producerService;
    }

    @PostMapping("/publish")
    public ResponseEntity<String> sendMessageToKafkaTopic(@RequestParam("message") String message) {
        producerService.sendMessage(message);
        return ResponseEntity.ok("Message sent to Kafka topic: " + message);
    }
}

์„ค๋ช…:

  • ์‚ฌ์šฉ์ž๊ฐ€ HTTP POST ์š”์ฒญ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๋ฉด, ํ•ด๋‹น ๋ฉ”์‹œ์ง€๊ฐ€ my_topic ์œผ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.
  • ์ „์†ก์ด ์™„๋ฃŒ๋˜๋ฉด ์„ฑ๊ณต ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ž…๋ ฅ ์˜ˆ์ œ:

  • HTTP ์š”์ฒญ: POST /api/kafka/publish?message=HelloKafka
  • ๊ฒฐ๊ณผ: Kafka ํ† ํ”ฝ์— “HelloKafka” ๋ฉ”์‹œ์ง€๊ฐ€ ์ „์†ก๋จ.

 


 

3. ํ”„๋กœ๋“€์„œ ์—ํฌ๋…ธ๋ ˆ์ง€๋จผํŠธ(Ack) ์ฒ˜๋ฆฌ

Kafka ํ”„๋กœ๋“€์„œ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ๋ธŒ๋กœ์ปค๋กœ ์ „์†กํ•œ ํ›„ Ack(ํ™•์ธ ์‘๋‹ต) ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ธŒ๋กœ์ปค์— ๋„์ฐฉํ–ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ACK ์„ค์ • ์€ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ๋ณด์žฅ์„ ์œ„ํ•ด ์ค‘์š”ํ•˜๋ฉฐ, ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค:
- acks=0 : ๋ธŒ๋กœ์ปค๊ฐ€ Ack๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Œ(๋‚ฎ์€ ์•ˆ์ •์„ฑ, ๋น ๋ฅธ ์„ฑ๋Šฅ).
- acks=1 : ๋ฆฌ๋” ๋ธŒ๋กœ์ปค์—์„œ๋งŒ ๋ฉ”์‹œ์ง€๋ฅผ ๊ธฐ๋กํ•˜๋ฉด Ack ์ „์†ก.
- acks=all : ๋ชจ๋“  ํŒ”๋กœ์›Œ ๋ธŒ๋กœ์ปค์— ๋ฉ”์‹œ์ง€๊ฐ€ ๊ธฐ๋ก๋œ ํ›„ Ack ์ „์†ก(๊ฐ€์žฅ ๋†’์€ ์•ˆ์ •์„ฑ).

Ack ์„ค์ • ์˜ˆ์ œ ( application.yml )

spring:
  kafka:
    producer:
      acks: all
      retries: 3
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer

์„ค๋ช…:

  • acks: all : ๋ชจ๋“  ๋ธŒ๋กœ์ปค์— ๋ฉ”์‹œ์ง€๊ฐ€ ์ €์žฅ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ ํ›„ ์„ฑ๊ณต ์ฒ˜๋ฆฌ.
  • retries: 3 : ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ ์‹œ 3๋ฒˆ๊นŒ์ง€ ์žฌ์‹œ๋„.

 


 

4. ํ”„๋กœ๋“€์„œ ์žฌ์‹œ๋„์™€ ๋ฒ„ํผ๋ง ์„ค์ •

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

์žฌ์‹œ๋„ ๋ฐ ๋ฒ„ํผ๋ง ์„ค์ • ์˜ˆ์ œ ( application.yml )

spring:
  kafka:
    producer:
      retries: 5  # ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ ์‹œ ์ตœ๋Œ€ 5๋ฒˆ ์žฌ์‹œ๋„
      batch-size: 16384  # ๋ฉ”์‹œ์ง€ ๋ฐฐ์น˜ ํฌ๊ธฐ (16KB)
      linger-ms: 10  # ๋ฐฐ์น˜ ์ „์†ก์„ ์œ„ํ•ด 10ms ๋Œ€๊ธฐ
      buffer-memory: 33554432  # ๋ฒ„ํผ ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ (32MB)

์„ค๋ช…:

  • retries : ๋ฉ”์‹œ์ง€ ์ „์†ก ์‹คํŒจ ์‹œ ์ตœ๋Œ€ 5๋ฒˆ๊นŒ์ง€ ์žฌ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.
  • batch-size : ๋ฐฐ์น˜๋กœ ์ „์†กํ•  ๋ฉ”์‹œ์ง€ ํฌ๊ธฐ๋ฅผ 16KB๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • linger-ms : ๋ฐฐ์น˜ ์ „์†ก์„ ์œ„ํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. 10ms ๋™์•ˆ ๋Œ€๊ธฐํ•˜์—ฌ ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ์•„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.
  • buffer-memory : ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๊ธฐ ์ „์— ์ž„์‹œ๋กœ ์ €์žฅํ•  ๋ฉ”๋ชจ๋ฆฌ ํฌ๊ธฐ๋ฅผ 32MB๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

 


 

Kafka ํ”„๋กœ๋“€์„œ ํ™œ์šฉ ํŠธ๋ Œ๋“œ ๋ฐ ํ†ต๊ณ„

์ตœ๊ทผ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ฐ€ ํ•„์š”ํ•œ ์‚ฐ์—…์—์„œ Kafka ํ”„๋กœ๋“€์„œ๋Š” ํ•„์ˆ˜์ ์ธ ๋„๊ตฌ๋กœ ์ž๋ฆฌ ์žก์•˜์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜ ์—์„œ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๋ฉฐ, ๊ธˆ์œต ์„œ๋น„์Šค , IoT , ๋กœ๊ทธ ์ˆ˜์ง‘ ๊ณผ ๊ฐ™์€ ๋ถ„์•ผ์—์„œ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

2023๋…„ ๊ฐœ๋ฐœ์ž ์กฐ์‚ฌ ์— ๋”ฐ๋ฅด๋ฉด, ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ๋Œ€๊ทœ๋ชจ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ Kafka ํ”„๋กœ๋“€์„œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ๊ทธ ์ค‘ 80% ์ด์ƒ์ด ๋ฐ์ดํ„ฐ ์†์‹ค ์—†์ด ์•ˆ์ •์ ์œผ๋กœ ์ „์†ก ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 


 

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ (FAQ)

Q1. Kafka ํ”„๋กœ๋“€์„œ์—์„œ acks ์„ค์ •์€ ์™œ ์ค‘์š”ํ•œ๊ฐ€์š”?
A1. acks ์„ค์ • ์€ ๋ฉ”์‹œ์ง€๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. acks=all ๋กœ ์„ค์ •ํ•˜๋ฉด ๋ชจ๋“  ๋ธŒ๋กœ์ปค๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•œ ํ›„ Ack๋ฅผ ๋ณด๋‚ด๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ์†์‹ค ๊ฐ€๋Šฅ์„ฑ์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Q2. Kafka ํ”„๋กœ๋“€์„œ์—์„œ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋Š” ๋ช‡ ๋ฒˆ์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋‚˜์š”?
A2. ์ผ๋ฐ˜์ ์œผ๋กœ 3~5ํšŒ ์ •๋„๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ ์ ˆํ•œ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

Q3. Kafka์—์„œ ๋ฐฐ์น˜ ์ „์†ก์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?
A3. ๋ฐฐ์น˜ ์ „์†ก ์€ ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ์•„์„œ ํ•œ ๋ฒˆ์— ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ค„์ด๊ณ , ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

Q4. Kafka ํ”„๋กœ๋“€์„œ์—์„œ ๋ฒ„ํผ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •์€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋‚˜์š”?
A4. ๋ฒ„ํผ ๋ฉ”๋ชจ๋ฆฌ ๋Š” ํ”„๋กœ๋“€์„œ๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ธŒ๋กœ์ปค๋กœ ์ „์†กํ•˜๊ธฐ ์ „์— ์ผ์‹œ์ ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„์ž…๋‹ˆ๋‹ค. ๋ฒ„ํผ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ถฉ๋ถ„ํžˆ ํฌ๋ฉด ๋” ๋งŽ์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ์•„ ํ•œ ๋ฒˆ์— ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Q5. Kafka ํ”„๋กœ๋“€์„œ๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ํ† ํ”ฝ์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‚˜์š”?
A5. ๋„ค, ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. KafkaTemplate ์˜ send ๋ฉ”์„œ๋“œ์—์„œ ํ† ํ”ฝ ์ด๋ฆ„์„ ๋‹ค๋ฅด๊ฒŒ ์ง€์ •ํ•˜๋ฉด ์—ฌ๋Ÿฌ ํ† ํ”ฝ์— ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€