Kafka 사용 패턴 - K8s 내부 통신
TL;DR
- Kafka 사용 패턴 - K8s 내부 통신의 핵심 개념과 사용 범위를 한눈에 정리
- 등장 배경과 필요한 이유를 짚고 실무 적용 포인트를 연결
- 주요 특징과 체크리스트를 빠르게 확인
1. 개념
┌─────────────────────────────────────────────────────────┐ │ K8s 내부 통신 패턴 │ │ │ │ ❌ 틀린 생각: │ │ "모든 서비스 간 통신에 Kafka 사용" │ │ │ │ ✅ 실제 패턴: │ │ "필요한 곳에만 Kafka, 나머지는 직접 통신" │ │ │ │ 경험적 비율: │ │ ├── 동기 (gRPC/HTTP): 70-80% │ │ └── 비동기 (Kafka): 20-30% │ │ │ └─────────────────────────────────────────────────────────┘
2. 배경
Kafka 사용 패턴 - K8s 내부 통신이(가) 등장한 배경과 기존 한계를 정리한다.
3. 이유
이 주제를 이해하고 적용해야 하는 이유를 정리한다.
4. 특징
- 1 동기 vs 비동기
- 2 결정 트리
- 왜 3번만 Kafka?
- gRPC vs HTTP/REST 선택
- 관련 키워드
5. 상세 내용
작성일: 2026-01-29 카테고리: Infra / Messaging / Architecture 포함 내용: Kafka, gRPC, 동기/비동기 통신, 이벤트 드리븐, 마이크로서비스 통신 패턴
1. 핵심 질문: 모든 곳에 Kafka?
┌─────────────────────────────────────────────────────────┐
│ K8s 내부 통신 패턴 │
│ │
│ ❌ 틀린 생각: │
│ "모든 서비스 간 통신에 Kafka 사용" │
│ │
│ ✅ 실제 패턴: │
│ "필요한 곳에만 Kafka, 나머지는 직접 통신" │
│ │
│ 경험적 비율: │
│ ├── 동기 (gRPC/HTTP): 70-80% │
│ └── 비동기 (Kafka): 20-30% │
│ │
└─────────────────────────────────────────────────────────┘
2. 일반적인 아키텍처
┌─────────────────────────────────────────────────────────────────────────┐
│ │
│ 외부 K8s 클러스터 │
│ │
│ ┌──────┐ ┌─────────┐ ┌──────────────────────────────────────┐ │
│ │ User │───►│ Ingress │───►│ API Gateway / BFF │ │
│ └──────┘ └─────────┘ └───────────────┬──────────────────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌──────────┐│
│ │ User │◄───────►│ Order │◄───────►│ Payment ││
│ │ Service │ gRPC │ Service │ gRPC │ Service ││
│ └────────────┘ HTTP └─────┬──────┘ └────┬─────┘│
│ │ │ │
│ │ Kafka │ │
│ ▼ (비동기만!) ▼ │
│ ┌──────────────────────────────┐ │
│ │ Kafka │ │
│ └──────────────────────────────┘ │
│ │ │ │
│ ┌─────────────────────┼─────────────────────┤ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Inventory │ │ Notification│ │ Analytics │ │
│ │ Service │ │ Service │ │ Service │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3. 통신 방식 선택 기준
3.1 동기 vs 비동기
┌─────────────────────────────────────────────────────────┐
│ │
│ 동기 통신 (gRPC, HTTP/REST): │
│ ├── 즉시 응답이 필요할 때 │
│ ├── 요청-응답 패턴 │
│ ├── 트랜잭션 처리 │
│ └── 예: 결제 확인, 사용자 인증, 재고 확인 │
│ │
│ 비동기 통신 (Kafka): │
│ ├── 응답을 기다릴 필요 없을 때 │
│ ├── 이벤트 발행 패턴 │
│ ├── 여러 서비스가 같은 이벤트 구독 │
│ ├── 처리 속도가 달라도 되는 경우 │
│ └── 예: 알림 발송, 로그 수집, 분석 데이터 │
│ │
└─────────────────────────────────────────────────────────┘
3.2 결정 트리
┌─────────────────────────────────────────────────────────┐
│ 선택 결정 트리 │
│ │
│ "이 통신에서..." │
│ │
│ 즉시 응답 필요? ─────────────────► Yes → gRPC/HTTP │
│ │ │
│ No │
│ ▼ │
│ 여러 소비자가 같은 메시지 필요? ──► Yes → Kafka │
│ │ │
│ No │
│ ▼ │
│ 메시지 유실되면 안 됨? ──────────► Yes → Kafka │
│ │ │
│ No │
│ ▼ │
│ 처리량 스파이크 대응 필요? ──────► Yes → Kafka │
│ │ │
│ No │
│ ▼ │
│ 단순 fire-and-forget? ─────────► 그냥 HTTP async 가능 │
│ │
└─────────────────────────────────────────────────────────┘
4. 실제 사례: 주문 처리 시나리오
┌─────────────────────────────────────────────────────────┐
│ │
│ 사용자: "주문하기" 버튼 클릭 │
│ │
│ 1. [동기 - gRPC] 재고 확인 │
│ Order Service ──► Inventory Service │
│ "재고 있어?" → "있어!" (즉시 응답 필요) │
│ │
│ 2. [동기 - gRPC] 결제 처리 │
│ Order Service ──► Payment Service │
│ "결제해줘" → "성공!" (트랜잭션, 즉시 필요) │
│ │
│ 3. [비동기 - Kafka] 주문 완료 이벤트 발행 │
│ Order Service ──► Kafka ──┬──► Notification Service │
│ ├──► Analytics Service │
│ ├──► Inventory Service │
│ └──► Shipping Service │
│ "주문 완료됐어~" (응답 안 기다림) │
│ │
│ 사용자에게 응답: "주문 완료!" (1,2번만 기다림) │
│ │
└─────────────────────────────────────────────────────────┘
왜 3번만 Kafka?
┌─────────────────────────────────────────────────────────┐
│ │
│ Kafka 쓰는 이유: │
│ ├── 여러 서비스가 동시에 "주문 완료" 알아야 함 │
│ ├── 알림 실패해도 주문은 유효 │
│ ├── 분석 서비스가 느려도 주문 응답엔 영향 없음 │
│ └── 나중에 새 서비스 추가해도 Order 수정 없이 구독만 │
│ │
│ gRPC 쓰는 이유 (1,2번): │
│ ├── 재고 없으면 주문 안 됨 → 즉시 확인 필요 │
│ ├── 결제 실패하면 주문 취소 → 트랜잭션 │
│ └── 사용자가 결과 기다리는 중 │
│ │
└─────────────────────────────────────────────────────────┘
5. Kafka 오버헤드 vs 장점
┌─────────────────────────────────────────────────────────┐
│ │
│ Kafka 오버헤드: │
│ ├── 레이턴시 증가 (직접 호출 대비 수~수십 ms 추가) │
│ ├── 운영 복잡도 (Zookeeper, Broker 관리) │
│ ├── 디버깅 어려움 (비동기 추적) │
│ ├── 메시지 순서 보장 복잡 │
│ └── 리소스 사용 (별도 클러스터 필요) │
│ │
│ Kafka 장점: │
│ ├── 디커플링 (서비스 간 의존성 감소) │
│ ├── 내구성 (메시지 영구 저장) │
│ ├── 확장성 (Consumer 추가 쉬움) │
│ ├── 버퍼링 (트래픽 스파이크 흡수) │
│ └── 리플레이 (과거 이벤트 재처리 가능) │
│ │
└─────────────────────────────────────────────────────────┘
6. 실무에서 흔한 패턴
┌─────────────────────────────────────────────────────────┐
│ │
│ 1. API Gateway 패턴 │
│ 외부 ──HTTP──► Gateway ──gRPC──► 내부 서비스들 │
│ │
│ 2. 내부 동기 통신 │
│ Service A ◄──gRPC──► Service B │
│ (빠르고, 타입 안전, 스트리밍 지원) │
│ │
│ 3. 이벤트 드리븐 (필요한 곳만) │
│ Service A ──Kafka──► [이벤트] ──► 여러 Consumer │
│ │
│ 4. Sidecar 패턴 (Istio 등) │
│ 서비스 간 통신은 Envoy Proxy가 처리 │
│ (mTLS, 로드밸런싱, 관측성) │
│ │
└─────────────────────────────────────────────────────────┘
gRPC vs HTTP/REST 선택
┌─────────────────────────────────────────────────────────┐
│ │
│ gRPC 선택: │
│ ├── 내부 서비스 간 통신 (K8s 내부) │
│ ├── 성능이 중요한 경우 │
│ ├── 양방향 스트리밍 필요 │
│ └── 강타입 계약 필요 (Proto) │
│ │
│ HTTP/REST 선택: │
│ ├── 외부 API (브라우저, 모바일) │
│ ├── 간단한 CRUD │
│ ├── 디버깅 용이성 필요 │
│ └── 다양한 클라이언트 지원 │
│ │
└─────────────────────────────────────────────────────────┘
7. Kafka가 적합한/불필요한 곳
┌─────────────────────────────────────────────────────────┐
│ │
│ Kafka가 적합한 곳: │
│ ├── 주문/결제 완료 이벤트 → 여러 후속 처리 │
│ ├── 로그/메트릭 수집 → 분석 시스템 │
│ ├── 사용자 활동 추적 → 추천/개인화 │
│ ├── CDC (Change Data Capture) → DB 동기화 │
│ ├── 외부 시스템 연동 → 버퍼링 필요 │
│ └── 비동기 작업 큐 → 이메일, 알림, 리포트 생성 │
│ │
│ Kafka 불필요한 곳: │
│ ├── 사용자 인증/인가 │
│ ├── 재고 조회 │
│ ├── 상품 상세 정보 │
│ ├── 즉각적인 CRUD 작업 │
│ ├── 동기적 트랜잭션 처리 │
│ └── 단순 요청-응답 패턴 │
│ │
└─────────────────────────────────────────────────────────┘
8. 대안 기술들
┌─────────────────────────────────────────────────────────┐
│ │
│ 메시지 브로커 선택: │
│ │
│ ┌──────────┬───────────────────────────────────────┐ │
│ │ 기술 │ 특징 │ │
│ ├──────────┼───────────────────────────────────────┤ │
│ │ Kafka │ 대용량, 영속성, 스트리밍, 복잡 │ │
│ │ RabbitMQ │ 경량, 유연한 라우팅, 전통적 MQ │ │
│ │ Redis │ 초경량, 임시 큐, Pub/Sub │ │
│ │ NATS │ 클라우드 네이티브, 경량, 빠름 │ │
│ │ Pulsar │ Kafka 대안, 멀티테넌시, 티어드 스토리지 │ │
│ └──────────┴───────────────────────────────────────┘ │
│ │
│ 선택 기준: │
│ ├── 단순 작업 큐 → RabbitMQ, Redis │
│ ├── 이벤트 스트리밍 → Kafka, Pulsar │
│ ├── 경량 Pub/Sub → Redis, NATS │
│ └── 대용량 로그 → Kafka │
│ │
└─────────────────────────────────────────────────────────┘
9. 정리
┌─────────────────────────────────────────────────────────┐
│ │
│ "모든 곳에 Kafka" = ❌ 안티패턴 │
│ │
│ 올바른 접근: │
│ ├── 동기 (gRPC/HTTP): 70-80% (대부분의 통신) │
│ │ └── 요청-응답, 트랜잭션, 즉시 필요 │
│ │ │
│ └── 비동기 (Kafka): 20-30% (선별적 사용) │
│ └── 이벤트 발행, 다수 구독자, 디커플링 필요 │
│ │
│ 핵심 원칙: │
│ ├── "즉시 응답 필요?" → 동기 │
│ ├── "여러 소비자?" → Kafka │
│ ├── "실패해도 괜찮아?" → Kafka │
│ └── "버퍼링 필요?" → Kafka │
│ │
│ 비유: │
│ ├── 동기 = 전화 (즉시 대화, 상대방 필수) │
│ └── 비동기 = 우체통 (보내고 끝, 나중에 확인) │
│ │
└─────────────────────────────────────────────────────────┘
관련 키워드
Kafka, gRPC, 마이크로서비스, 이벤트 드리븐, 동기/비동기, 메시지 브로커, K8s, 서비스 간 통신