비동기(Asynchronous)라는 단어는 Kafka, Redis, WebFlux, Reactor 등 다양한 곳에서 자주 등장한다.
하지만 문맥마다 “비동기”의 의미는 다르다.
이 글에서는 메시징(Messageing) 과 리액티브(Reactive) 가 말하는 비동기가 무엇이 다른지, 그리고 왜 구분해야 하는지를 명확히 정리한다.
| 구분 | 메시징 시스템 (Kafka, Redis) | Spring WebFlux / Reactor |
|---|---|---|
| 비동기 의미 | 시스템 간 통신 비동기 | 쓰레드 단위의 논리 비동기 |
| 적용 범위 | 서비스 ↔ 서비스 (네트워크 간) | 애플리케이션 내부 코드 흐름 |
| 대표 키워드 | Producer / Consumer / Broker | Mono / Flux / Publisher / Subscriber |
| 목적 | 서비스 간 결합도 낮추기, 이벤트 지연 제거 | 논블로킹, 고동시성, 리소스 효율 |
즉,
Kafka나 Redis 같은 메시징 시스템은 여러 서비스 간 데이터를 주고받을 때 사용된다.
핵심은 “보내는 쪽은 즉시 응답을 기다리지 않는다”는 것이다.
[전략 서버] → [Kafka Broker] → [거래 서버]
이 구조의 장점은 다음과 같다.
메시지(Message) 는 이 과정의 데이터 단위다.
예를 들어 다음 JSON 한 건이 메시지 한 단위다.
{
"symbol": "BTCUSDT",
"price": 67520.5,
"timestamp": 1710241200,
"signal": "BUY"
}
Kafka나 Redis는 이런 메시지를 큐 형태로 저장하고,
다른 서비스가 구독(Subscribe)하여 처리한다.
Spring WebFlux의 비동기란
하나의 서버 내부에서 요청을 처리할 때 쓰레드가 블로킹되지 않는 구조를 말한다.
예시:
@GetMapping("/price")
public Mono<PriceDto> getPrice() {
return webClient.get()
.uri("https://api.binance.com/price")
.retrieve()
.bodyToMono(PriceDto.class);
}
여기서 WebClient는 요청을 보낸 뒤 응답을 기다리지 않는다.
응답이 도착하면 그 시점에 Mono 체인이 이어서 실행된다.
즉,
이것이 리액티브 프로그래밍의 핵심, 즉 “데이터 스트림에 반응하는” 비동기이다.
| 특징 | 설명 |
|---|---|
| Non-blocking | I/O 작업 중 쓰레드가 대기하지 않음 |
| Event-driven | 데이터가 도착하면 콜백 체인으로 자동 처리 |
| Stream 기반 | Mono(단일 데이터), Flux(다중 데이터) 형태 |
| Backpressure | 소비자가 감당할 만큼만 데이터 수신 |
예시:
Flux.fromIterable(List.of("BTC", "ETH", "XRP"))
.flatMap(symbol -> webClient.get()
.uri("/price?symbol=" + symbol)
.retrieve()
.bodyToMono(PriceDto.class))
.subscribe(price -> System.out.println("가격 수신: " + price));
이 코드는 여러 API를 비동기적으로 동시에 호출하고,
각 응답이 올 때마다 순서에 상관없이 스트림처럼 처리한다.
| 구분 | 메시징 비동기 | 리액티브 비동기 |
|---|---|---|
| 동작 영역 | 네트워크 / 시스템 간 | 애플리케이션 내부 |
| 단위 | Message | Mono / Flux |
| 시간 축 | 서비스 간 지연 허용 | 코드 실행 흐름 제어 |
| 목적 | 서비스 decoupling | 쓰레드 효율, 응답성 향상 |
| 예시 | Kafka, Redis Pub/Sub | WebFlux, Reactor |
즉,
// 메시지 발행 (비동기 전송)
kafkaTemplate.send("order.topic", orderEvent);
→ 메시지를 보내고 즉시 반환됨.
Consumer가 나중에 처리한다.
return webClient.get()
.uri("/api/price")
.retrieve()
.bodyToMono(PriceDto.class)
.map(price -> price.calculateFee());
→ I/O 대기 없이 다른 요청도 병렬로 처리 가능.
응답이 오면 Reactor가 map 체인을 실행한다.
| 관점 | 메시징 비동기 | 리액티브 비동기 |
|---|---|---|
| 비유 | 택배 배송 시스템 | 공장 내 컨베이어벨트 |
| 설명 | 발신자는 물건 보내고 끝 (나중에 배송됨) | 물건이 컨베이어를 타고 올 때마다 기계가 반응 |
| 처리 주체 | 여러 서버 간 | 하나의 서버 내부 |
메시징 비동기
→ 시스템 간 통신 단위.
→ Kafka, Redis, RabbitMQ 같은 메시지 브로커 중심.
→ “데이터를 보내놓고 나중에 처리”하는 구조.
리액티브 비동기
→ 코드 실행 단위.
→ Spring WebFlux, Reactor 기반.
→ “데이터가 도착할 때마다 반응”하는 구조.
Kafka는 네트워크 레벨의 비동기,
WebFlux는 애플리케이션 내부의 논리 비동기라고 생각하면 된다.
비동기라는 단어는 하나지만,
Kafka에서의 비동기와 WebFlux의 비동기는 전혀 다른 세계의 개념이다.
이 둘은 상호 대체 관계가 아니라, 서로 보완 관계다.
실무에서는 Kafka로 외부 이벤트를 비동기 전달하고,
내부에서는 WebFlux로 효율적으로 처리하는 식으로 함께 사용된다.