Kafka의 핵심 설계 원리
Kafka의 Decoupling, Buffering, Fan-out, Replay와 Load Balancing 원리를 서비스 구조와 함께 정리한다.
Decoupling + Buffering + Fan-out + Replay + Load Balancing
Decoupling
서비스 간 직접 의존성을 끊는 것
REST 직접 호출이면:
Order Service
↓ REST
Payment Service
Order Service는 반드시 Payment Service를 알아야 한다.
그래서 뭐.. 아래와 같은 사항을 알아야 한다.
- 주소는?
- API는?
- 지금 상태가?
- 응답은 언제 오니?
- 실패하면 어떻게 처리?
딱 봐도 귀찮잖아요?
그래서 Kafka에서는 이 의존성을 줄여버린다.
Order Service
↓
ORDER_CREATED
↓
Kafka
↓
Payment Service
Order Service는 Payment Service를 몰라도 된다.
Order Service가 ORDER_CREATED라는 이벤트를 발행하기만 하면, Payment Service는 ORDER_CREATED를 소비하는 것으로 만들어 줄 수 있다.
말로 하니깐 좀 헷갈리긴 하는데,
Order ─X─ Payment
Order → Kafka ← Payment
이와 같이 구성할 수 있다.
정리
서비스와 서비스를 직접 연결하지 않고 이벤트를 매개로 연결
Decoupling = 서비스 사이의 결합도를 낮추는 것
Buffering
처리 속도 차이를 Kafka가 중간에서 흡수하는 것
자자 주문이 폭주했다고 쳐보자,
Order Service 초당 10,000건 발생
Payment Service 초당 3,000건 처리 가능
직접 호출하면
Order → Payment
↑
감당 못함
Payment에 요청이 몰리면서 장애가 날 수 있다.
하지만~ 킹갓 개발자성님들이 만들어놓은 Kafka가 있다면
이러만 문제를 해결해 줄 수 있다
Producer
초당 10,000
↓
Kafka
██████████████
↓
Consumer
초당 3,000
Kafka는 Consumer가 지금 못 처리한 7,000건을 Kafka가 일단 가지고 있고,
Consumer는 자기 속도 처리에 맞춰서
1
2
3
4
5
...
계속 처리하면 된다.
쉽게 말하면 Kafka가 대기줄 역할
식당으로 생각하면..
- 손님 100명
- 번호표 뽑기
- 대기열
- 직원들이 주문을 순차로 쳐냄
정리
순간적인 트래픽 폭증이 바로 Consumer 장애로 이어지는 것을 줄인다.
Buffering = Producer와 Consumer의 처리 속도 차이를 중간에서 흡수
Fan-out
하나의 이벤트를 여러 시스템이 각각 이용할 수 있는 것
예를 들어
ORDER_CREATED
↓
Kafka
│
┌────┼──────┬──────┐
↓ ↓ ↓ ↓
결제 재고 이메일 분석
주문 이벤트 하나 생성되었다고 하자,
- Payment: 결제 처리
- Inventory: 재고 감소
- Email: 주문 완료 메일
- Analytics: 매출 통계
와 같은 각자 같은 이벤트를 다른 목적으로 사용한다.
특히 중요한 건 Producer가:
- Payment가 있는지
- Email이 있는지
- Analytics가 있는지
굳이 알 필요가 없다.
그래서 확장이 매우 용이하다
서비스를 계속 추가할 수 있다
Kafka
│
┌────┬────┬──┴────┬────────┐
↓ ↓ ↓ ↓ ↓
결제 재고 이메일 분석 사기탐지
Producer는 안 건드려도 될 수 있다.
Fan-out = 하나의 이벤트를 여러 독립적인 Consumer에게 전달
Replay (중요)
Kafka의 중요한 특징
과거 이벤트를 다시 읽을 수 있다.
Kafka에는 이런 로그가 있다고 해보자
offset
100 ORDER_CREATED
101 ORDER_PAID
102 ORDER_CREATED
103 ORDER_CANCELLED
104 ORDER_CREATED
105 ORDER_PAID
Analytics Service가 버그 때문에 100~105를 잘못 처리했다고 할 때,
Kafka에서는 offset을 다시 돌려서 다시 읽을 수 있는 기능을 제공한다.
현재
↓
100 101 102 103 104 105
↑
offset reset
↓
100 101 102 103 104 105
예를 들어 AI팀이 새로운 추천 모델을 만들었다고 해보자. 과거 3개월 주문 데이터를 다시 흘려서:
Kafka 과거 이벤트
↓
새로운 AI 모델
↓
재처리
와 같이 처리할 수도 있다.
정리
- 버그 수정 후 재처리
- 새로운 Consumer 추가
- 데이터 재계산
- 분석 파이프라인 복원
등에 유용하다.
Replay = 저장된 과거 이벤트를 다시 소비할 수 있는 기능
Load Balancing
한 서비스의 처리량을 여러 서버에 나눠주는 것
Payment Service가 한 대라고 생각해보자
Kafka
↓
Payment A
이 경우에 트래픽이 많아지면 감당하기가 힘들어진다.
그래서 Payment 서버를 3개 띄운다.
Kafka
↓
payment-group
┌──────┼──────┐
↓ ↓ ↓
A B C
Kafka는 Partition을 기반으로 이벤트를 나눠준다.
예를 들어 Topic에 Partition이 3개라면:
- Partition 0 → Payment A
- Partition 1 → Payment B
- Partition 2 → Payment C
그러면 처리량을 분산할 수 있다.
주문 1 → A
주문 2 → B
주문 3 → C
주문 4 → A
...
Kafka에서는 이걸 Consumer Group이라는 개념으로 구현
중요한 차이는
- 서로 다른 Consumer Group → 같은 이벤트를 각각 받음
- 같은 Consumer Group → 이벤트를 나눠서 처리
Kafka
┌────────┼─────────┐
↓ ↓ ↓
payment-group email-group analytics-group
│ │ │
P1 P2 P3 E1 E2 A1 A2 A3
Payment 내부에서는:
- P1
- P2
- P3
Load Balancing = 같은 역할을 하는 여러 Consumer가 이벤트 처리량을 분산
결론
ORDER_CREATED
↓
Order Service ─────────> Kafka
│
│ Buffering
│ 이벤트를 쌓아둠
│
┌──────────────┼──────────────┐
↓ ↓ ↓
payment-group email-group analytics-group
│ │ │
P1 P2 P3 E1 E2 A1 A2
여기서
| 개념 | 의미 |
|---|---|
| Decoupling | Order와 Payment가 직접 연결되지 않음 |
| Buffering | Consumer가 느려도 Kafka가 이벤트를 보관 |
| Fan-out | 같은 이벤트를 Payment, Email, Analytics가 각각 사용 |
| Replay | 이미 지나간 이벤트를 다시 읽을 수 있음 |
| Load Balancing | Payment 서버 여러 대가 작업을 나눠 처리 |
Kafka가 이벤트를 저장한다
↓
Buffering 가능
↓
Consumer가 나중에 읽을 수 있음
↓
Replay 가능
Producer와 Consumer가 Kafka로 분리됨
↓
Decoupling
↓
여러 Consumer가 붙을 수 있음
↓
Fan-out
Consumer Group을 여러 인스턴스로 구성
↓
Load Balancing
그래서 결론적으로는 Kafka는 이벤트를 중간에 저장해서 Producer와 Consumer를 분리하고, 여러 Consumer가 각자의 속도로 이벤트를 독립적으로 처리하거나 재처리하고, 필요하면 여러 서버로 처리량까지 분산할 수 있게 해주는 분산 이벤트 스트리밍 플랫폼
COMMENTS
GitHub 계정으로 로그인하여 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions에 공개 저장되며, 작성 내용과 GitHub 프로필 정보가 다른 방문자에게 보일 수 있습니다.