아래는 **"스프링부트 웹플럭스 시리즈"**의 **4장: 리액티브 데이터 스트림 이해"**에 대한 초안입니다. 3장에서의 실습을 바탕으로 `Mono`와 `Flux`를 중심으로 리액티브 스트림의 개념을 설명하고, 간단한 예제를 포함했습니다. 코드도 간략히 유지하며 초보자가 이해하기 쉽게 작성했습니다.

---

## 4. 리액티브 데이터 스트림 이해

3장에서 우리는 첫 번째 웹플럭스 애플리케이션을 만들며 `Mono`를 살짝 맛봤습니다. 이번 장에서는 웹플럭스의 핵심인 리액티브 데이터 스트림을 깊이 파고들어, `Mono`와 `Flux`가 무엇인지, 어떻게 동작하는지 알아보겠습니다. 실습도 곁들이며 개념을 확실히 잡아볼게요. 준비되셨죠?

### Mono와 Flux의 개념

리액티브 프로그래밍의 세계에서 데이터는 "스트림" 형태로 흐릅니다. 이 스트림을 다루는 두 가지 주요 도구가 바로 `Mono`와 `Flux`입니다. 둘 다 스프링 웹플럭스가 사용하는 리액터(Reactor) 라이브러리에서 제공되며, 비동기 데이터 처리를 가능하게 합니다.

- **Mono**: 0개 또는 1개의 항목을 발행하는 스트림입니다. 단일 값을 반환할 때 유용합니다. 예를 들어, 데이터베이스에서 한 명의 사용자 정보를 조회하거나, 외부 API에서 단일 응답을 받을 때 사용합니다.
- **Flux**: 0개 이상의 항목을 발행하는 스트림입니다. 여러 개의 데이터를 순차적으로 처리하거나, 실시간으로 계속 들어오는 데이터를 다룰 때 적합합니다. 리스트나 스트리밍 데이터가 대표적인 예입니다.

쉽게 말해, `Mono`는 "하나 아니면 없음"이고, `Flux`는 "여러 개가 올 수도 있음"이라고 생각하면 됩니다. 이 둘은 리액티브 스트림의 기본 빌딩 블록으로, 데이터를 비동기적으로 생성하고 구독자가 이를 소비하는 구조를 만듭니다.

### 리액티브 스트림의 동작 원리

리액티브 스트림은 "발행-구독(Publish-Subscribe)" 모델을 따릅니다. 데이터가 준비되면 발행자(Publisher)가 이를 발행하고, 구독자(Subscriber)가 그 데이터를 받아 처리합니다. 이 과정에서 중요한 점은 **비동기성**과 **백프레셔(Backpressure)**입니다.

- **비동기성**: 데이터가 준비되는 즉시 처리하지 않고, 준비 완료 시점에 맞춰 반응합니다. 스레드가 블록되지 않으니 자원을 효율적으로 사용할 수 있죠.
- **백프레셔**: 구독자가 데이터 처리 속도를 조절할 수 있게 해줍니다. 예를 들어, 데이터가 너무 빨리 쏟아지면 "천천히 보내줘"라고 요청할 수 있는 셈입니다.

`Mono`와 `Flux`는 이런 원리를 구현한 도구로, 우리가 작성하는 코드는 이 흐름을 정의하는 역할을 합니다.

### 간단한 예제로 배우는 Mono와 Flux

이제 직접 코드를 보며 느낌을 익혀보겠습니다. 3장에서 만든 프로젝트에 새 컨트롤러를 추가하거나, 별도의 클래스에서 테스트해볼 수 있습니다. 여기서는 간단히 컨트롤러로 예제를 작성합니다.

`src/main/java/com/example/demo`에 `StreamController`를 만들고 아래 코드를 추가하세요:

```java
package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;

@RestController
public class StreamController {

    @GetMapping("/mono")
    public Mono<String> getMono() {
        return Mono.just("This is a Mono!")
                   .delayElement(Duration.ofSeconds(1));
    }

    @GetMapping("/flux")
    public Flux<String> getFlux() {
        return Flux.just("This", "is", "a", "Flux!")
                   .delayElements(Duration.ofSeconds(1));
    }
}
```

- `/mono` 엔드포인트: `Mono`로 단일 문자열을 1초 지연 후 반환합니다. 접속하면 1초 뒤에 "This is a Mono!"가 표시됩니다.
- `/flux` 엔드포인트: `Flux`로 여러 문자열을 1초 간격으로 순차적으로 발행합니다. 접속하면 "This", "is", "a", "Flux!"가 1초씩 간격을 두고 나타납니다(클라이언트에 따라 한꺼번에 보일 수도 있음).

애플리케이션을 실행하고 `http://localhost:8080/mono`와 `http://localhost:8080/flux`를 브라우저나 Postman으로 테스트해보세요. `Mono`는 한 번에 끝나고, `Flux`는 여러 값을 순차적으로 보내는 걸 느낄 수 있습니다.

더 재미있는 예제로, 숫자 스트림을 만들어볼까요?

```java
@GetMapping("/numbers")
public Flux<Integer> getNumbers() {
    return Flux.range(1, 5)
               .delayElements(Duration.ofSeconds(1));
}
```

`/numbers`에 접속하면 1부터 5까지 숫자가 1초 간격으로 출력됩니다. 이런 식으로 `Flux`는 연속적인 데이터를 다룰 때 강력합니다.

### 잠깐 정리

- `Mono`: 단일 데이터(0 또는 1개)를 비동기적으로 처리.
- `Flux`: 여러 데이터(0개 이상)를 스트림으로 처리.
- 동작: 발행자가 데이터를 준비하면 구독자가 받아서 처리하며, 비동기와 백프레셔로 효율성을 높임.

이 예제들은 아주 기본적인 수준이지만, 리액티브 스트림의 흐름을 이해하는 데 큰 도움이 됩니다. 실제로는 데이터베이스나 외부 API와 연동할 때 더 빛을 발휘하죠.

### 마무리

`Mono`와 `Flux`는 웹플럭스의 심장과도 같습니다. 이 두 도구를 잘 다룰 수 있다면, 비동기 프로그래밍의 세계가 훨씬 친근하게 느껴질 겁니다. 다음 장에서는 웹플럭스의 라우팅 방식을 더 깊이 탐구하며, 함수형 접근법도 함께 살펴보겠습니다. 이번 장에서 스트림의 맛을 보셨으니, 다음 단계가 더 기대되시죠?

---

이 장은 개념 설명과 간단한 실습을 균형 있게 배치해 초보자가 부담 없이 따라 할 수 있도록 했습니다. 코드도 최소화했으며, 추가 예제나 설명이 필요하면 언제든 말씀해주세요!