🌏 소스 코드
https://github.com/gitchan-Study/kafka-playground
GitHub - gitchan-Study/kafka-playground
Contribute to gitchan-Study/kafka-playground development by creating an account on GitHub.
github.com
🌏 인트로
이 포스팅에서는 Spring Boot와 Kafka를 사용하여 "회원가입"이라는 하나의 이벤트가 발생했을 때, "쿠폰 발급"과 "이메일 발송"이라는 두 가지 후속 작업이 어떻게 독립적으로 처리될 수 있는지 보여주는 예제 프로젝트에 대해 설명하겠습니다.
미니 프로젝트로 진행한 만큼 카프카를 원래 사용하는 목적이라면 대용량 트래픽을 감당하기 위한 것이 대부분이라 여러 대의 서버로 사용하지만, 개념만 이해를 하기 위해서 로컬에서 구성할 수 있도록 만들었습니다.
기본적인 카프카 개념이나 설정에 대해서 이해할 수 있도록 최대한 쉽고 간단한 설계로 설명하려고 합니다.
🌏 Kafka
✅ 카프카 쓰는 이유
전통적인 방식으로는 회원가입 로직 안에 쿠폰 발급 코드와 이메일 발송 코드가 모두 포함되어야 합니다.
@Transactional
public void register(User user) {
userRepository.save(user); // 회원 저장
couponService.issueWelcomeCoupon(user); // 쿠폰 발급
emailService.sendWelcomeEmail(user); // 이메일 발송
}
이 경우, 만약 이메일 시스템에 장애가 발생하면 회원가입 전체 프로세스가 실패할 수 있습니다. 이를 강한 결합(Tightly Coupled) 이라고 합니다.
- 쿠폰 서버나 이메일 서버 중 하나라도 장애가 발생하면 전체 회원가입이 실패합니다.
- 각 기능이 강하게 결합되어 유지보수가 어렵습니다.
- 새로운 후속 기능(예: 알림톡 발송)을 추가하려면 register() 내부를 매번 수정해야 합니다.
이 프로젝트는 Kafka라는 메시지 브로커를 중간에 두어 이 문제를 해결하는 것을 목표로 합니다.
[회원가입 API] --> [Kafka Topic: user-registered] --> [CouponConsumer]
\\
--> [EmailConsumer]
- 회원가입 시스템은 "회원가입이 완료되었다"는 이벤트만 Kafka에 던져주고 자신의 역할을 끝냅니다.
- 쿠폰 시스템과 이메일 시스템은 Kafka를 구독하고 있다가, 해당 이벤트가 발생하면 각자 독립적으로 자신의 작업을 수행합니다.
이를 통해 각 시스템의 의존성이 제거되어 느슨한 결합(Loosely Coupled) 을 가진 유연하고 안정적인 아키텍처를 만들 수 있습니다.
✅ 개념
Kafka는 대용량의 실시간 데이터를 안정적으로 처리하기 위한 분산 이벤트 스트리밍 플랫폼입니다. 이 프로젝트에서는 여러 시스템이 서로 직접 통신하지 않고, Kafka를 통해 메시지(이벤트)를 주고받도록 하는 메시지 브로커의 역할로 사용되었습니다.
- Producer: 메시지를 생산하여 Kafka에 보내는 역할 (이 프로젝트에서는 UserController)
- Consumer: Kafka로부터 메시지를 받아서 소비(처리)하는 역할 (이 프로젝트에서는 CouponConsumer, EmailConsumer)
- Topic: 메시지가 저장되는 공간의 이름 (이 프로젝트에서는 user-registered)
- Zookeeper: Kafka 클러스터의 상태를 관리하고 조정하는 역할
✅ 설정 방법 (Docker를 이용한 로컬 설정)
로컬 환경에서 Kafka와 Zookeeper를 가장 쉽게 실행하는 방법은 Docker를 사용하는 것입니다. 프로젝트 루트의 docker-compose.yml 파일이 이 역할을 담당합니다.
version: '3'
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.0.1
container_name: zookeeper
ports:
- "2181:2181"
# ...
kafka:
image: confluentinc/cp-kafka:7.0.1
container_name: kafka
ports:
- "9092:9092"
depends_on:
- zookeeper
# ...
docker compose up -d 명령어 하나로 내 컴퓨터에 Kafka와 Zookeeper가 격리된 환경에서 실행됩니다.
🌏 프로젝트 설명
✅ 로컬 실행 환경 구성
이 프로젝트를 실행하면 다음과 같이 여러 애플리케이션이 각자의 위치와 포트에서 실행됩니다.
애플리케이션 실행 위치 포트 번호 역할
| Spring Boot App | 내 PC (macOS) | localhost:8080 | API 서버, Kafka Producer |
| Kafka Broker | Docker 컨테이너 | localhost:9092 | 메시지 중개 |
| Zookeeper | Docker 컨테이너 | localhost:2181 | Kafka 클러스터 관리 |
✅ 회원가입 API 실행 흐름
사용자가 회원가입 API를 호출했을 때, 전체 시스템이 동작하는 흐름은 다음과 같습니다.

- 요청: 사용자가 id와 password를 담아 /register API를 호출합니다.
- 처리 및 발행: UserController는 사용자 정보를 내부 Map에 저장하고, UserRegisteredEvent 객체를 생성하여 user-registered 토픽으로 이벤트를 발행(Produce)합니다.
- 독립적인 소비
- coupon-group ID를 가진 CouponConsumer가 토픽으로부터 이벤트를 받아 쿠폰 발급 로직을 수행합니다.
- email-group ID를 가진 EmailConsumer가 동일한 토픽으로부터 이벤트를 받아 이메일 발송 로직을 수행합니다.
- groupId가 다르기 때문에 두 Consumer는 같은 이벤트를 각각 한 번씩 소비할 수 있습니다.
https://engineerinsight.tistory.com/435
[아키텍처/Kafka] 비동기 메시징 시스템: 개념 + Consumer Group을 통한 병렬 처리의 원리를 간단히 알
🌏 비동기 메시징 시스템이란?✅ 먼저, 비동기(Asynchronous)란?동기: 요청을 보내고 응답을 받을 때까지 기다림비동기: 요청을 보내고 응답을 기다리지 않고 다른 일 진행메시징 시스템은 일단 메
engineerinsight.tistory.com

도움이 되었다면, 공감/댓글을 달아주면 깃짱에게 큰 힘이 됩니다!🌟
비밀댓글과 메일을 통해 오는 개인적인 질문은 받지 않고 있습니다. 꼭 공개댓글로 남겨주세요!
'아키텍처+MSA' 카테고리의 다른 글
| [아키텍처/캐시] Redis 캐시 완전 정복: 개념·전략·TTL·일관성·모니터링 총정리 (0) | 2025.11.20 |
|---|---|
| [아키텍처] 로드밸런싱 완전 정복: L4/L7 구조부터 SPOF 해결까지 (0) | 2025.11.20 |
| [아키텍처/Kafka] 메세지 전송 보장 방식(At most once, At least once, Exactly once): 특징과 EOS 구현 방법 (0) | 2025.09.17 |
| [아키텍처/Kafka] acks(Acknowledgement) 설정: acks=0,1,all (0) | 2025.09.17 |
| [아키텍처/Kafka] 메세지 복제(Replication)와 브로커의 Leader-Follower 구조 (0) | 2025.09.17 |