Kafka ์ ๋ฌธ. ์๋น์ค๊ฐ ์ปค์ง๋ฉด "์ฃผ๋ฌธ์ด ์๊ธฐ๋ฉด ์๋ฆผ ๋ณด๋ด๊ณ , ์ฌ๊ณ ์ค์ด๊ณ , ํต๊ณ ์๊ณ ..."๊ฐ ๊ฑฐ๋ฏธ์ค์ฒ๋ผ ์ฝํ๋ค. Kafka๋ ์ด ํ๋ฆ์ ์ด๋ฒคํธ๋ก ํ์ด๋ธ๋ค. Producer·Consumer·Topic·Partition ๊ฐ์ ํต์ฌ ๊ฐ๋ ๋ถํฐ Spring ์ฝ๋๊น์ง ์ ๋ฆฌํ๋ค.
๋ค์ด๊ฐ๋ฉฐ
๋ฐฐ์น์ ์คํธ๋ฆผ ์ฒ๋ฆฌ ๊ธ์์ Kafka๋ฅผ ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ๋ํ ๋๊ตฌ๋ก ์ ๊น ๋ค๋ค๋ค. ์ด๋ฒ์ ๊ทธ Kafka๋ฅผ ์ ๋๋ก ๋ค์ฌ๋ค๋ณธ๋ค.
์๋น์ค๊ฐ ์์ ๋ ๋ชจ๋ ๊ฑธ ์ง์ ํธ์ถํ๋ฉด ๋๋ค. "์ฃผ๋ฌธ์ด ๋ค์ด์ค๋ฉด ๊ฒฐ์ ํ๊ณ , ์ฌ๊ณ ์ค์ด๊ณ , ์ด๋ฉ์ผ ๋ณด๋ด๊ณ , ํต๊ณ ์๋๋ค." ๊ทธ๋ฐ๋ฐ ์ด ํ์ ์์ ์ด ๋์ด๋ ์๋ก ์ฃผ๋ฌธ ์ฝ๋๊ฐ ๋ชจ๋ ๊ฑธ ์์์ผ ํ๋ ๊ฑฐ๋ฏธ์ค์ด ๋๋ค. ํ๋๊ฐ ๋๋ ค์ง๋ฉด ์ ์ฒด๊ฐ ๋๋ ค์ง๊ณ , ํ๋๊ฐ ์ฃฝ์ผ๋ฉด ์ฃผ๋ฌธ๊น์ง ์คํจํ๋ค.
Kafka๋ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ฒคํธ(event) ๋ผ๋ ๋ฐ์์ผ๋ก ํผ๋ค. "์ฃผ๋ฌธ์ด ์๊ฒผ๋ค"๋ ์ฌ์ค ํ๋๋ง ๋์ง๋ฉด, ๊ทธ๊ฑธ ํ์๋ก ํ๋ ์์คํ ๋ค์ด ๊ฐ์ ์์์ ๊ฐ์ ธ๊ฐ ์ฒ๋ฆฌํ๋ค. ๋ณด๋ด๋ ์ชฝ๊ณผ ๋ฐ๋ ์ชฝ์ด ์๋ก๋ฅผ ๋ชฐ๋ผ๋ ๋๋ค.
Kafka์ ํต์ฌ์ "๋ฐ์ดํฐ๋ฅผ ์ง์ ์ ๋ฌํ์ง ์๊ณ , ํ๋ฅด๋ ํต๋ก์ ํ๋ ค๋ณด๋ธ๋ค"๋ ๊ฒ์ด๋ค. ๋ณด๋ด๋ ์ชฝ๊ณผ ๋ฐ๋ ์ชฝ์ด ๋ถ๋ฆฌ๋๋ฉด ์์คํ ์ด ์ ์ฐํด์ง๋ค.
์ด ๊ธ์์๋ Kafka์ ํต์ฌ ๊ฐ๋ ๊ณผ ๋์ ์๋ฆฌ๋ฅผ ์ก๊ณ , Spring์ผ๋ก ์ค์ ์ฝ๋๋ฅผ ์์ฑํด๋ณธ๋ค.
Kafka๋
Apache Kafka๋ ๋ถ์ฐ ์ด๋ฒคํธ ์คํธ๋ฆฌ๋ฐ ํ๋ซํผ์ด๋ค. 2011๋ ๋งํฌ๋์ธ์์ ๋ง๋ค์ด์ก๊ณ , ์ง๊ธ์ ๋์ฉ๋ ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ฌ์ค์ ํ์ค์ด๋ค.
์ฝ๊ฒ ๋งํ๋ฉด ๊ฑฐ๋ํ๊ณ ๋น ๋ฅธ ๋ฉ์์ง ํต๋ก๋ค. ํ์ชฝ์์ ๋ฐ์ดํฐ(์ด๋ฒคํธ)๋ฅผ ํ๋ ค๋ณด๋ด๋ฉด, ๋ค๋ฅธ ์ชฝ์์ ๊ทธ๊ฑธ ๋ฐ์ ์ฒ๋ฆฌํ๋ค. ํต์ฌ ํน์ง์ ์ ์ด๋ค.
- ๊ณ ์ฑ๋ฅ: ์ด๋น ์๋ฐฑ๋ง ๊ฑด์ ๋ฉ์์ง๋ฅผ ์ฒ๋ฆฌํ๋ค.
- ํ์ฅ์ฑ: ์๋ฒ๋ฅผ ์ฌ๋ฌ ๋๋ก ๋๋ ค ๋ถํ๋ฅผ ๋ถ์ฐํ๋ค.
- ์์์ฑ: ๋ฉ์์ง๋ฅผ ๋์คํฌ์ ์ ์ฅํด, ์๋น์๊ฐ ๋์ค์ ์ฝ์ด๋ ๋๋ค. (๋ฉ์์ง๊ฐ ์ฌ๋ผ์ง์ง ์์)
๋ง์ง๋ง ํน์ง์ด ์ ํต์ ์ธ ๋ฉ์์ง ํ์์ ํฐ ์ฐจ์ด๋ค. Kafka๋ ์ฝ์๋ค๊ณ ๋ฉ์์ง๋ฅผ ์ง์ฐ์ง ์๋๋ค. ์ ํด์ง ๊ธฐ๊ฐ ๋์ ๋ณด๊ดํด์, ์ฌ๋ฌ ์๋น์๊ฐ ๊ฐ์ ๋ค๋ฅธ ์๋๋ก ์ฝ์ ์ ์๋ค.
ํต์ฌ ๊ฐ๋
Kafka๋ฅผ ์ดํดํ๋ ค๋ฉด ๋ค ๊ฐ๋ ์ ์ก์์ผ ํ๋ค.
| ๊ฐ๋ | ์ญํ |
| Producer | ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋(๋ณด๋ด๋) ์ชฝ |
| Consumer | ์ด๋ฒคํธ๋ฅผ ๊ตฌ๋ ํ๋(๋ฐ๋) ์ชฝ |
| Topic | ์ด๋ฒคํธ๊ฐ ์์ด๋ ์นดํ ๊ณ ๋ฆฌ๋ณ ํต๋ก |
| Partition | Topic์ ๋๋ ๋จ์ (๋ณ๋ ฌ ์ฒ๋ฆฌ·ํ์ฅ์ ํต์ฌ) |

ํ๋ฆ์ ๋จ์ํ๋ค. Producer๊ฐ Topic์ ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋ฉด, ๊ทธ Topic์ ๊ตฌ๋ ํ๋ Consumer๋ค์ด ์ด๋ฒคํธ๋ฅผ ๊ฐ์ ธ๊ฐ ์ฒ๋ฆฌํ๋ค. ์ค๊ฐ์ Kafka๊ฐ ์ด๋ฒคํธ๋ฅผ ์์ ํ๊ฒ ๋ณด๊ดํ๊ณ ์ ๋ฌํ๋ค.
Topic๊ณผ Partition
Topic์ ์ด๋ฒคํธ์ ์นดํ ๊ณ ๋ฆฌ๋ค. "orders", "payments", "user-signups"์ฒ๋ผ ์ข ๋ฅ๋ณ๋ก ํต๋ก๋ฅผ ๋๋๋ค.
Partition์ ํ๋์ Topic์ ์ฌ๋ฌ ์กฐ๊ฐ์ผ๋ก ๋๋ ๊ฒ์ด๋ค. ์ด๊ฒ Kafka ์ฑ๋ฅ์ ํต์ฌ์ด๋ค. Topic์ ํํฐ์ 3๊ฐ๋ก ๋๋๋ฉด, 3๊ฐ์ Consumer๊ฐ ๋์์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ ์ ์๋ค. ํํฐ์ ์ ๋๋ฆฌ๋ฉด ์ฒ๋ฆฌ๋์ด ๋์ด๋๋ค.
Topic: orders
โ Partition 0 → Consumer A
โ Partition 1 → Consumer B
โ Partition 2 → Consumer C (3๋ฐฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ)
๊ฐ์ ํค(์: user_id)๋ฅผ ๊ฐ์ง ์ด๋ฒคํธ๋ ํญ์ ๊ฐ์ ํํฐ์ ์ผ๋ก ๊ฐ์, ์์๊ฐ ๋ณด์ฅ๋๋ค. ํ ์ฌ์ฉ์์ ์ฃผ๋ฌธ ์์๊ฐ ๋ค๋ฐ๋์ง ์๋๋ค.
Consumer Group
์ฌ๋ฌ Consumer๋ฅผ ๋ฌถ์ ๊ฒ Consumer Group์ด๋ค. ๊ฐ์ ๊ทธ๋ฃน ์์์๋ ํํฐ์ ์ ๋๋ ๊ฐ์ ธ์ ๋ถํ๋ฅผ ๋ถ์ฐํ๊ณ , ๋ค๋ฅธ ๊ทธ๋ฃน๋ผ๋ฆฌ๋ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ๋๋ค.
Topic: orders
โ Group "์ฌ๊ณ ๊ด๋ฆฌ" → ์ฌ๊ณ ์ฐจ๊ฐ (orders๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ)
โ Group "ํต๊ณ" → ํต๊ณ ์ง๊ณ (๊ฐ์ orders๋ฅผ ๋ ๋ฐ์ ์ฒ๋ฆฌ)
orders ํ ํฝ ํ๋๋ฅผ ์ฌ๊ณ ํ๊ณผ ํต๊ณํ์ด ์๋ก ์ํฅ ์์ด ๊ฐ์ ์๋นํ๋ค. ์ด๊ฒ ์ด๋ฒคํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ์ ํ์ด๋ค.
Spring์ผ๋ก Producer ๋ง๋ค๊ธฐ
์ด์ ์ฝ๋๋ก ๋ณด์. ์ฃผ๋ฌธ์ด ์๊ธธ ๋๋ง๋ค ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋ Producer๋ค. ๋จผ์ ์ค์ .
# application.yml
spring:
kafka:
bootstrap-servers: localhost:9092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
consumer:
group-id: order-service
auto-offset-reset: earliest
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
properties:
spring.json.trusted.packages: "*"
์ด๋ฒคํธ ๊ฐ์ฒด์ Producer ์ฝ๋.
// ๋ฐํํ ์ด๋ฒคํธ (record๋ก ๊ฐ๋จํ)
public record OrderEvent(Long orderId, Long userId, int amount) {}
@Service
public class OrderEventProducer {
private final KafkaTemplate<String, OrderEvent> kafkaTemplate;
public OrderEventProducer(KafkaTemplate<String, OrderEvent> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public void publish(OrderEvent event) {
// key๋ฅผ userId๋ก → ๊ฐ์ ์ฌ์ฉ์ ์ด๋ฒคํธ๋ ๊ฐ์ ํํฐ์
(์์ ๋ณด์ฅ)
kafkaTemplate.send("orders", String.valueOf(event.userId()), event);
}
}
์ฃผ๋ฌธ ์๋น์ค๋ ์ด์ ํ์ ์์ ์ ์ง์ ํธ์ถํ์ง ์๋๋ค. ์ด๋ฒคํธ๋ง ๋ฐํํ๊ณ ๋์ด๋ค.
@Service
public class OrderService {
private final OrderEventProducer producer;
public void createOrder(OrderRequest req) {
Order order = orderRepository.save(req.toEntity());
// ํ์ ์์
(์ฌ๊ณ ·์๋ฆผ·ํต๊ณ)์ ์ง์ ๋ถ๋ฅด์ง ์๊ณ ์ด๋ฒคํธ๋ง ๋ฐํ
producer.publish(new OrderEvent(
order.getId(), order.getUserId(), order.getAmount()));
// ์ดํ ๋๊ฐ ๋ฌด์์ ํ๋์ง OrderService๋ ๋ชจ๋ฅธ๋ค
}
}
Spring์ผ๋ก Consumer ๋ง๋ค๊ธฐ
๋ฐํ๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๋ Consumer๋ค์ด๋ค. @KafkaListener ํ๋๋ฉด ๋๋ค.
@Service
public class InventoryConsumer {
// "์ฌ๊ณ ๊ด๋ฆฌ" ๊ทธ๋ฃน์ผ๋ก orders๋ฅผ ๊ตฌ๋
@KafkaListener(topics = "orders", groupId = "inventory")
public void handle(OrderEvent event) {
// ์ฌ๊ณ ์ฐจ๊ฐ
inventoryService.decrease(event.orderId());
log.info("์ฌ๊ณ ์ฐจ๊ฐ ์๋ฃ: order={}", event.orderId());
}
}
@Service
public class NotificationConsumer {
// "์๋ฆผ" ๊ทธ๋ฃน์ผ๋ก ๊ฐ์ orders๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ๊ตฌ๋
@KafkaListener(topics = "orders", groupId = "notification")
public void handle(OrderEvent event) {
// ์ฃผ๋ฌธ ํ์ธ ์๋ฆผ ๋ฐ์ก
notificationService.send(event.userId(), "์ฃผ๋ฌธ์ด ์๋ฃ๋์์ต๋๋ค");
}
}
๋ Consumer๋ ์๋ก ๋ค๋ฅธ ๊ทธ๋ฃน์ด๋ผ, ๊ฐ์ ์ฃผ๋ฌธ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ๋๋ค. ์ฌ๊ณ ์ฐจ๊ฐ๊ณผ ์๋ฆผ ๋ฐ์ก์ด ์๋ก ์ํฅ์ ์ฃผ์ง ์๋๋ค. ์๋ฆผ ์๋ฒ๊ฐ ์ ์ ์ฃฝ์ด๋ ์ฌ๊ณ ์ฐจ๊ฐ์ ๋ฉ์ฉกํ ๋์๊ฐ๊ณ , ์๋ฆผ ์๋ฒ๊ฐ ์ด์๋๋ฉด Kafka์ ๋ณด๊ด๋ ์ด๋ฒคํธ๋ฅผ ์ด์ด์ ์ฒ๋ฆฌํ๋ค.
์ ํ์ ์์ ์ ์ถ๊ฐํ๊ณ ์ถ์ผ๋ฉด? ์ ๊ทธ๋ฃน์ Consumer๋ฅผ ํ๋ ๋ ๋ง๋ค๋ฉด ๋์ด๋ค. ๊ธฐ์กด ์ฝ๋๋ ํ ์ค๋ ์ ๋ฐ๊พผ๋ค.
@Service
public class StatsConsumer {
@KafkaListener(topics = "orders", groupId = "stats")
public void handle(OrderEvent event) {
statsService.record(event); // ํต๊ณ ์ง๊ณ ์ถ๊ฐ — ๊ธฐ์กด ์ฝ๋ ๋ณ๊ฒฝ ์์
}
}
์ง์ ํธ์ถ vs Kafka
Kafka๋ฅผ ์ฐ๋ฉด ๋ฌด์์ด ๋ฌ๋ผ์ง๋์ง ๋น๊ตํ๋ฉด ๋ถ๋ช ํ๋ค.
| ์ง์ ํธ์ถ | Kafka (์ด๋ฒคํธ) | |
| ๊ฒฐํฉ๋ | ์ฃผ๋ฌธ์ด ๋ชจ๋ ํ์์ ์ | ์๋ก ๋ชจ๋ฆ (๋์จํจ) |
| ํ์ ์ถ๊ฐ | ์ฃผ๋ฌธ ์ฝ๋ ์์ | Consumer๋ง ์ถ๊ฐ |
| ์ฅ์ ์ ํ | ํ๋ ์ฃฝ์ผ๋ฉด ์ฃผ๋ฌธ ์คํจ | ๊ฒฉ๋ฆฌ๋จ (๋ ๋ฆฝ) |
| ๋ถํ | ๋๊ธฐ ์ฒ๋ฆฌ๋ก ๋๋ ค์ง | ๋น๋๊ธฐ๋ก ํ๋ ค๋ณด๋ |
| ์ฌ์ฒ๋ฆฌ | ์ด๋ ค์ | ๋ณด๊ด๋ ์ด๋ฒคํธ ์ฌ์๋น |
๋์์ธ ํจํด ๊ธ์์ ๋ค๋ฃฌ ์ต์ ๋ฒ ํจํด์, ์์คํ ๋ ๋ฒจ๋ก ํ์ฅํ ๊ฒ์ด๋ผ๊ณ ๋ณผ ์ ์๋ค. ๋ฐํ์์ ๊ตฌ๋ ์๋ฅผ ๋ถ๋ฆฌํ๋ ๊ทธ ๋ฐ์์ด Kafka์์๋ ์๋น์ค ๊ฐ ํต์ ์ผ๋ก ์ปค์ง๋ค.
์ธ์ ์ฐ๊ณ , ์ธ์ ์ ์ฐ๋
Kafka๊ฐ ๋ง๋ฅ์ ์๋๋ค. ๋์ ํ๋ฉด ์ด์ํ ์ธํ๋ผ๊ฐ ํ๋ ๋ ์๊ธด๋ค.
Kafka๊ฐ ์ด์ธ๋ฆฌ๋ ๊ฒฝ์ฐ
- ํ๋์ ์ด๋ฒคํธ์ ์ฌ๋ฌ ์์คํ ์ด ๋ฐ์ํด์ผ ํ ๋
- ์๋น์ค ๊ฐ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ณ ์ถ์ ๋ (MSA)
- ๋์ฉ๋ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ํ๋ ค๋ณด๋ด์ผ ํ ๋
- ๋ก๊ทธ ์์ง, ์ด๋ฒคํธ ์์ฑ, ์ค์๊ฐ ํ์ดํ๋ผ์ธ
๊ตณ์ด ํ์ ์๋ ๊ฒฝ์ฐ
- ์๋น์ค๊ฐ ์๊ณ ํ์ ์์ ์ด ๋จ์ํ ๋ → ์ง์ ํธ์ถ์ด ๋ ๊ฐ๋จ
- ์ฆ๊ฐ์ ์ธ ์๋ต์ด ๊ผญ ํ์ํ ๋ (Kafka๋ ๋น๋๊ธฐ)
- ํธ๋ํฝ์ด ์ ์ด ๋ฉ์์ง ํ๊ฐ ๊ณผํ ๊ฒฝ์ฐ
์์ ์๋น์ค์ Kafka๋ฅผ ๊น๋ฉด ์ด์ ๋ณต์ก๋๋ง ๋์ด๋๋ค. "์ด๋ฒคํธ์ ์ฌ๋ฌ ์์คํ ์ด ๋ฐ์ํด์ผ ํ๋" ์ํฉ์ด ๋์ ๋๊ฐ ๋์ ํ์ด๋ฐ์ด๋ค.
๋ง์น๋ฉฐ
Kafka๋ "๋ฐ์ดํฐ๋ฅผ ์ง์ ์ ๋ฌํ๋" ๋ฐฉ์์ "์ด๋ฒคํธ๋ฅผ ํ๋ ค๋ณด๋ด๋" ๋ฐฉ์์ผ๋ก ๋ฐ๊พผ๋ค. ๊ทธ ๊ฒฐ๊ณผ ๋ณด๋ด๋ ์ชฝ๊ณผ ๋ฐ๋ ์ชฝ์ด ๋ถ๋ฆฌ๋๊ณ , ์์คํ ์ด ์ ์ฐํด์ง๋ค. ์ฃผ๋ฌธ ์๋น์ค๋ ๊ทธ์ "์ฃผ๋ฌธ์ด ์๊ฒผ๋ค"๊ณ ์ธ์น๊ณ , ์ฌ๊ณ ·์๋ฆผ·ํต๊ณ๋ ๊ฐ์ ์์์ ๋ฐ์ํ๋ค.
ํต์ฌ๋ง ๋ค์ ์ง์ผ๋ฉด, Producer๊ฐ Topic์ ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๊ณ , Partition์ผ๋ก ๋ณ๋ ฌ ์ฒ๋ฆฌ๋๋ฉฐ, Consumer Group์ด ๊ฐ์ ๋ ๋ฆฝ์ ์ผ๋ก ์๋นํ๋ค. ์ด ๊ตฌ์กฐ ์์์ ๋์จํ ๊ฒฐํฉ, ์ฅ์ ๊ฒฉ๋ฆฌ, ์์ฌ์ด ํ์ฅ์ด ๊ฐ๋ฅํด์ง๋ค.
๋ฌผ๋ก ๋ชจ๋ ๊ณณ์ ํ์ํ ๊ฑด ์๋๋ค. ํ์ง๋ง ์๋น์ค๊ฐ ์ปค์ง๊ณ ์ด๋ฒคํธ์ ๋ฐ์ํ ์์คํ ์ด ๋์ด๋ ๋, Kafka๋ ๊ฑฐ๋ฏธ์ค ๊ฐ์ ์ง์ ํธ์ถ์ ๊น๋ํ ์ด๋ฒคํธ ํ๋ฆ์ผ๋ก ๋ฐ๊ฟ์ค๋ค. ๊ทธ๊ฒ ๋ง์ ํ์ฌ๊ฐ Kafka๋ฅผ ์ฐ๋ ์ด์ ๋ค.
์ฐธ๊ณ ์ถ์ฒ
- Apache Kafka ๊ณต์ ๋ฌธ์ — https://kafka.apache.org/documentation/
- Spring for Apache Kafka — https://docs.spring.io/spring-kafka/reference/
- Confluent: What is Kafka? — https://www.confluent.io/what-is-apache-kafka/
'๐ Data Science & AI > Data Engineering' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| Airflow๋ก ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ๋ง๋ค๊ธฐ (2) | 2026.06.24 |
|---|---|
| ETL, ELT ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ๋ ๋ฐฉ์, ๋ญ๊ฐ ๋ค๋ฅผ๊น (0) | 2026.06.16 |
| Spark๋ฅผ Kubernetes ์์ ์ฌ๋ฆฌ๋ฉด ๋ฌด์์ด ๋ฌ๋ผ์ง๋๊ฐ (0) | 2026.04.20 |
| ๋ฐ์ดํฐ ์ข ๋ฅ์ ์ดํด์ ๋ถ์ ํ๋ก์ธ์ค (0) | 2026.02.27 |