<aside>
1️⃣ 왜 Spring과 Kafka인가?
</aside>
- 둘의 관계:
- Spring Boot는 Kafka와 쉽게 통합할 수 있어, 빠르고 안정적인 데이터 스트리밍이 가능하다.
- Spring Boot의 auto-configuration 기능을 통해 Kafka 설정을 간소화할 수 있다.
- 중요성:
- 실시간 분석, 로그 수집, 데이터 레이크 구축 등 다양한 분야에서 활용된다.
- 또한, 마이크로서비스 아키텍처에서 이벤트 기반의 비동기 통신을 가능하게 한다.
- 현업 사례:
- 실시간 주식 가격 분석: 주식 가격의 실시간 변동을 분석하여 트레이딩 시스템에 반영
- 로그 모니터링: 서비스의 로그 데이터를 실시간으로 수집하여 모니터링 및 알림
- 추천 시스템: 사용자의 행동 데이터를 실시간으로 분석하여 개인화된 추천 제공
<aside>
2️⃣ Spring Boot와 Kafka의 아키텍처
</aside>
- Producer, Broker, Consumer의 관계:
- Producer:
- 데이터를 생성하여 Kafka에 전달하는 컴포넌트. Spring에서는 **
KafkaTemplate
**을 사용하여 구현할 수 있습니다.
- Broker:
- Kafka 서버 인스턴스로, 데이터를 저장하고 전달하는 역할을 합니다.
- Consumer:
- Kafka로부터 데이터를 가져가는 컴포넌트. Spring에서는
@KafkaListener
어노테이션을 사용하여 구현합니다.
- 컴포넌트
- Topics: 데이터의 카테고리나 이름. 하나의 토픽은 하나 이상의 파티션으로 구성됩니다.
- Partitions: 토픽을 물리적으로 나누는 단위. 파티션을 통해 데이터의 병렬 처리가 가능합니다.
- Offsets: 파티션 내에서 메시지의 위치를 나타내는 순번입니다.
- 데이터 흐름
- Producer -> Broker -> Consumer:
- Producer:
KafkaTemplate.send()
메서드를 사용하여 메시지를 특정 토픽의 특정 파티션에 전송합니다.
- Broker: 전달받은 메시지를 해당 토픽의 파티션에 저장합니다.
- Consumer: **
@KafkaListener
**를 통해 특정 토픽의 메시지를 구독하고 처리합니다.
<aside>
3️⃣ Kafka 파티션의 중요성
</aside>
- 고가용성
- 파티션 복제:
- Kafka에서는 하나의 파티션을 여러 브로커에 복제할 수 있다. 이로 인해 하나의 브로커가 다운되더라도 다른 브로커에서 해당 파티션의 데이터를 사용할 수 있어 고가용성이 보장된다.
- 리더와 팔로워:
- 각 파티션 복제본 중 하나는 리더가 되고, 나머지는 팔로워가 된다.
- 리더가 실패할 경우, 팔로워 중 하나가 새로운 리더가 되어 서비스가 중단되지 않는다.
- 성능 향상
- 병렬 처리:
- 파티션을 여러 브로커에 분산시키면, 쓰기와 읽기 연산이 병렬로 처리될 수 있다. 이로 인해 전체 시스템의 처리량(throughput)과 응답 시간(latency)이 개선된다.
- 로드 밸런싱:
- 여러 파티션과 브로커를 사용하면, 부하가 고르게 분산되므로 단일 브로커에 부하가 집중되는 것을 방지할 수 있다.
- 순서 보장
- 파티션 내 순서:
- Kafka는 하나의 파티션 내에서만 메시지의 순서를 보장한다. 따라서, 순서가 중요한 작업을 수행할 때는 해당 메시지들을 같은 파티션에 넣어야 한다.
- 확장성과 순서 보장의 Trade-off:
- 여러 파티션을 사용하면 확장성이 높아지지만, 전체 메시지에 대한 순서는 보장되지 않는다. 따라서, 어플리케이션의 요구사항에 따라 파티션을 적절히 설계해야 한다.
<aside>
4️⃣ Spring Kafka: 실제 구현
</aside>
- 코드 예시: **
@KafkaListener
**와 KafkaTemplate
사용 예시
// Producer
@Service
public class KafkaProducerService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String topic, String message) {
kafkaTemplate.send(topic, message);
}
}
// Consumer
@Service
public class KafkaConsumerService {
@KafkaListener(topics = "myTopic", groupId = "myGroup")
public void listen(String message) {
System.out.println("Received Message: " + message);
}
}
- 설명: 어떻게 메시지를 보내고 받는지
- Producer: **
KafkaTemplate
**을 사용하여 메시지를 특정 토픽으로 보낼 수 있습니다.
- Consumer:
@KafkaListener
어노테이션을 사용하여 특정 토픽에서 메시지를 받을 수 있습니다.
<aside>
5️⃣ 주의점과 베스트 프랙티스
</aside>
- 키 선택
- 키를 잘 선택하면 데이터가 파티션에 균등하게 분산됩니다.
- 예를 들어, 사용자 ID나 주문 ID 같은 고유한 키를 사용할 수 있습니다.
- 컨슈머 그룹
- 컨슈머 수는 파티션 수와 일치하거나 작아야 합니다.
- 그렇지 않으면, 일부 컨슈머는 메시지를 받지 못할 수 있습니다.