마이크로서비스 아키텍처에서 이벤트 기반 통신은 서비스 간의 느슨한 결합을 지원하며, 확장성과 유연성을 향상시킵니다. 이 포스팅에서는 스프링 클라우드 스트림(Spring Cloud Stream)과 Apache Kafka를 사용하여 마이크로서비스 간의 이벤트 기반 통신을 구현하는 방법을 소개합니다.
스프링 클라우드 스트림이란?
스프링 클라우드 스트림은 메시지 기반 마이크로서비스를 구축하기 위한 프레임워크입니다. 개발자가 특정 메시지 브로커의 API에 직접 의존하지 않고, 메시지 기반의 커뮤니케이션을 손쉽게 구현할 수 있게 해줍니다. 스프링 클라우드 스트림은 메시지 브로커를 추상화하는 바인더(binder)라는 개념을 도입하여, Kafka, RabbitMQ와 같은 다양한 메시지 브로커를 동일한 프로그래밍 모델로 사용할 수 있습니다.
Apache Kafka란?
Apache Kafka는 분산 스트리밍 플랫폼으로, 대량의 데이터를 신뢰성 있게 처리하고 전달할 수 있습니다. Kafka는 높은 처리량, 확장성, 내구성을 제공하며, 실시간 데이터 분석과 모니터링을 위해 널리 사용됩니다.
예제 시나리오: 쇼핑몰의 주문, 결제, 배송 처리
온라인 쇼핑몰에서 사용자가 상품을 주문하면, 다음과 같은 과정을 거치게 됩니다.
- 주문 처리: 사용자가 상품을 주문하면 주문 이벤트가 생성되고 Kafka 토픽에 발행됩니다.
- 결제 처리: 사용자가 주문에 대한 결제를 완료하면 결제 이벤트가 생성되고 Kafka 토픽에 발행됩니다.
- 배송 처리: 결제가 완료되면 상품이 배송되고 배송 이벤트가 Kafka 토픽에 발행됩니다.
각 단계의 이벤트는 주문 키를 기준으로 Kafka 토픽에 저장되며, 이 이벤트들은 MongoDB에 저장됩니다.
프로젝트 설정
plugins {
id("org.springframework.boot") version "2.5.5"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
id("org.jetbrains.kotlin.jvm") version "1.5.31"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation("org.springframework.cloud:spring-cloud-starter-stream-kafka")
implementation("org.springframework.kafka:spring-kafka")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
dependencyManagement {
imports {
mavenBom("org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}")
}
}
설정 파일
application.yml
spring:
cloud:
stream:
kafka:
binder:
brokers: localhost:9092 # Kafka 브로커 주소
bindings:
input:
destination: shopping-mall-events
group: order-processing-group
output:
destination: shopping-mall-events
data:
mongodb:
uri: mongodb://localhost:27017/orderdb
logging:
level:
org.springframework.kafka: DEBUG
여기서 shopping-mall-events는 사용할 Kafka 토픽 이름이고, order-processing-group은 Kafka Consumer Group 이름입니다.
공통 이벤트 클래스 정의
모든 이벤트 타입을 하나의 공통 클래스로 처리할 수 있도록 정의합니다.
data class Event(
val type: EventType,
val key: String,
val status: String
)
enum class EventType {
ORDER, PAYMENT, SHIPPING
}
이벤트 발행 및 수신 변경
하나의 토픽을 사용하므로, 발행 및 수신하는 방식을 약간 수정해야 합니다.
이벤트 발행 서비스
@Service
class OrderService(private val orderProcessor: Source) {
fun createOrder(orderKey: String) {
// 주문 처리 로직
val event = Event(EventType.ORDER, orderKey, OrderStatus.PROCESSED.name)
orderProcessor.output().send(MessageBuilder.withPayload(event).build())
}
fun processPayment(orderKey: String) {
// 결제 로직
val event = Event(EventType.PAYMENT, orderKey, PaymentStatus.PAID.name)
orderProcessor.output().send(MessageBuilder.withPayload(event).build())
}
fun shipOrder(orderKey: String) {
// 배송 로직
val event = Event(EventType.SHIPPING, orderKey, ShippingStatus.SHIPPED.name)
orderProcessor.output().send(MessageBuilder.withPayload(event).build())
}
}
이벤트 수신 서비스
@Service
class OrderEventListener(private val mongoTemplate: MongoTemplate) {
@StreamListener(target = Sink.INPUT)
fun handleEvent(event: Event) {
when (event.type) {
EventType.ORDER -> handleOrderEvent(event)
EventType.PAYMENT -> handlePaymentEvent(event)
EventType.SHIPPING -> handleShippingEvent(event)
}
}
private fun handleOrderEvent(event: Event) {
// 주문 이벤트 처리
mongoTemplate.save(event)
}
private fun handlePaymentEvent(event: Event) {
// 결제 이벤트 처리
mongoTemplate.save(event)
}
private fun handleShippingEvent(event: Event) {
// 배송 이벤트 처리
mongoTemplate.save(event)
}
}
이번 포스팅에서는 스프링 클라우드 스트림과 Apache Kafka를 사용하여 마이크로서비스 간의 이벤트 기반 통신을 구현하는 방법에 대해 살펴보았습니다. 이러한 방법을 사용하면 서비스 간의 결합도를 낮추면서도 강력한 데이터 흐름 제어 및 이벤트 처리를 구현할 수 있습니다. 이는 마이크로서비스 아키텍처를 구축할 때 매우 중요한 부분입니다.
'SpringBoot' 카테고리의 다른 글
JMX (Java Management Extensions) 이해하기 및 모니터링 도구 (0) | 2023.10.29 |
---|---|
마이크로서비스 추적을 위한 Spring Cloud Sleuth와 Zipkin 사용예제 (1) | 2023.10.22 |
몽고디비를 활용한 주문 프로세스 관리: 스텝별 상태 저장 및 조회 (0) | 2023.10.22 |
스프링의 RedisLockRegistry를 활용한 제한된 상품의 동시성 제어 및 주문 처리 (0) | 2023.10.09 |
스프링 부트에서 외부 API 서비스를 병렬 처리하여 응답하는 방법 (0) | 2023.10.09 |