| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 |
- 배열
- Eclipse
- 자바
- input
- ArrayList
- java테스트
- 자바스크립트
- 테스트자동화
- 자바문법
- vscode
- html
- Java
- math
- Array
- js
- junit5
- javascript
- Visual Studio Code
- 단위테스트
- HashMap
- list
- 문자열
- IntelliJ
- 인텔리제이
- junit
- SpringBoot
- CSS
- 스프링부트
- string
- 정규식
- Today
- Total
어제 오늘 내일
[Spring Boot] "이벤트가 1초에 10만 개?" 대용량 처리를 위한 Kafka 연동 기초 (Producer/Consumer) 본문
[Spring Boot] "이벤트가 1초에 10만 개?" 대용량 처리를 위한 Kafka 연동 기초 (Producer/Consumer)
hi.anna 2026. 3. 28. 08:55
쇼핑몰에서 "주문 버튼"을 눌렀다고 가정해 봅시다.
- 주문 정보 DB 저장
- 재고 감소
- 결제 승인
- 배송 요청
- 사용자에게 알림톡 발송
- 데이터 분석팀에 로그 전송
이 모든 걸 한 번의 HTTP 요청(Controller) 안에서 순차적으로 처리하면 어떻게 될까요?
알림톡 서버가 1초만 늦게 응답해도, 사용자는 주문 완료 화면을 못 보고 뱅글뱅글 도는 로딩만 보게 됩니다.
오늘은 이 강한 결합(Tight Coupling)을 끊어내고, 초당 수십만 건의 데이터도 거뜬히 처리하는 메시지 큐의 제왕, Apache Kafka를 스프링 부트에 연동해 보겠습니다.
1. 왜 Kafka 인가요? (RabbitMQ vs Kafka)
"메시지 큐(Message Queue)라면 RabbitMQ도 있잖아요?"
맞습니다. 하지만 목적이 다릅니다.
- RabbitMQ: 메시지를 안전하게 전달하고 삭제하는 것이 목표. (복잡한 라우팅 가능)
- Kafka: 메시지를 로그(파일)로 저장하고, 엄청난 속도(Throughput)로 처리하는 것이 목표. (대용량 로그, 실시간 스트리밍에 특화)
카프카는 "생산자(Producer)"가 데이터를 던져놓으면, "소비자(Consumer)"가 자기가 처리할 수 있는 속도로 가져가는 구조입니다. 덕분에 서버가 터지지 않고 안정적으로 돌아갑니다.
2. 설치하기 (Docker Compose)
카프카는 설치가 좀 까다롭습니다. 주키퍼(Zookeeper)라는 코디네이터가 필요하기 때문인데요. Docker Compose를 쓰면 3분 컷입니다.
docker-compose.yml
version: '3'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
docker-compose up -d로 실행하면 준비 끝!
3. 스프링 부트 설정 (의존성 추가)
build.gradle
dependencies {
implementation 'org.springframework.kafka:spring-kafka'
}
application.yml
spring:
kafka:
bootstrap-servers: localhost:9092 # 카프카 서버 주소
consumer:
group-id: my-group # 소비자 그룹 ID (중요!)
auto-offset-reset: earliest # 처음부터 다 읽을래?(earliest) 아니면 지금부터 읽을래?(latest)
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
Tip: 카프카는 모든 데이터를 Byte 배열로 주고받습니다. 그래서 보낼 때(Serializer)와 받을 때(Deserializer) "이거 문자열이야!"라고 알려줘야 합니다.
4. 메시지 보내기 (Producer)
주문이 발생했을 때 "주문 생성됨"이라는 메시지를 카프카에 던져봅시다.
@Service
@RequiredArgsConstructor
@Slf4j
public class KafkaProducerService {
private final KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String topic, String message) {
// topic: 메시지 주제 (예: "order_create")
// message: 보낼 데이터 (보통 JSON 문자열)
kafkaTemplate.send(topic, message);
log.info("Kafka Message Sent: topic={}, msg={}", topic, message);
}
}
Controller에서 호출:
producer.sendMessage("order_create", "주문번호:1234, 사용자:홍길동");
이렇게 하면 컨트롤러는 카프카에 던지자마자 즉시 리턴합니다. (0.01초 소요) 알림톡이 늦게 가든 말든 사용자는 쾌적합니다.
5. 메시지 받기 (Consumer)
이제 누군가는 그 메시지를 받아서 뒷수습(알림 발송, 로그 저장)을 해야겠죠?
@Service
@Slf4j
public class KafkaConsumerService {
// 1. topics: 구독할 주제
// 2. groupId: 내 소속 그룹 (같은 그룹끼리는 메시지를 나눠서 처리함)
@KafkaListener(topics = "order_create", groupId = "my-group")
public void consume(String message) {
log.info("Kafka Message Received: {}", message);
// 여기서 무거운 작업을 수행합니다.
// ex) 알림톡 발송 (3초 걸림)
// ex) DB에 로그 저장
}
}
서버를 켜두면 콘솔창에 Kafka Message Received: 주문번호:1234...가 찍히는 걸 볼 수 있습니다.
6. 핵심 개념: Consumer Group (확장성)
카프카의 꽃은 Consumer Group입니다.
주문이 폭주해서 1초에 1,000건이 들어오는데, Consumer 서버가 1대라서 처리가 느리다면?
그냥 똑같은 Consumer 서버를 2대 더 띄우세요. (groupId를 똑같이 해서)
카프카가 알아서 파티션(Partition)을 나눠서 병렬 처리를 시켜줍니다. 서버를 늘리는 만큼 처리 속도도 정비례해서 빨라집니다. 이게 바로 카프카가 대용량 처리에 강한 이유입니다.
마치며
오늘의 결론입니다.
- Kafka를 쓰면 "요청"과 "처리"를 분리(Decoupling)할 수 있다.
- Producer는 던지고 잊어버리고(Fire and Forget), Consumer는 자기 속도대로 처리한다.
- 서버를 늘리는 것(Scale-out)만으로 처리량을 무한대로 확장할 수 있다.
이제 여러분의 시스템은 트래픽이 몰려도 터지지 않고, 메시지를 차곡차곡 쌓아뒀다가 안전하게 처리할 수 있게 되었습니다.
다음 포스팅에서는 "RDB에서 LIKE %검색어% 쓰면 느려터져요..." 1억 건 데이터에서도 0.1초 만에 검색 결과를 찾아주는 Elasticsearch 검색 엔진 구축에 대해 알아보겠습니다.
도움이 되셨다면 좋아요와 댓글 부탁드립니다! 😊
