| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
- junit5
- Visual Studio Code
- 테스트자동화
- IntelliJ
- 배열
- java테스트
- string
- 단위테스트
- input
- HashMap
- javascript
- junit
- CSS
- 인텔리제이
- Array
- 정규식
- list
- vscode
- 문자열
- 자바스크립트
- 자바
- SpringBoot
- ArrayList
- 자바문법
- Eclipse
- 스프링부트
- js
- Java
- math
- html
- Today
- Total
어제 오늘 내일
[Reactive] "데이터가 강물처럼 흐른다?" 리액티브 스트림즈(Reactive Streams)와 Backpressure 완벽 이해 본문
[Reactive] "데이터가 강물처럼 흐른다?" 리액티브 스트림즈(Reactive Streams)와 Backpressure 완벽 이해
hi.anna 2026. 3. 31. 00:13
자바 개발자에게 데이터란 무엇일까요? 보통 List, Map 같은 컬렉션에 담긴 "완성된 결과물"을 의미했습니다.
DB에서 100만 건을 조회하면, 100만 건이 다 메모리에 올라올 때까지 기다렸다가 한 번에 List로 받아서 처리했죠. (Memory: "살려줘...")
하지만 리액티브 프로그래밍(Reactive Programming)에서는 다릅니다.
데이터는 고여있는 호수가 아니라, 끊임없이 흐르는 강물(Stream)과 같습니다.
오늘은 WebFlux의 뼈대가 되는 표준 사양, 리액티브 스트림즈(Reactive Streams)와 그 핵심 기능인 백프레셔(Backpressure)를 알아보겠습니다.
1. Iterable(과거) vs Reactive Streams(미래)
가장 큰 차이는 "누가 주도권을 쥐고 있는가?"입니다.
- Iterable (
for-each): 소비자가 주도합니다. - "냉장고(List) 문 열어. 사과 하나 꺼내(
next()). 또 꺼내. 더 없어? 끝." - 데이터가 이미 준비되어 있어야 합니다.
- Reactive Streams (
Publisher-Subscriber): 생산자가 주도하되, 소비자가 조절합니다. - "나 구독할게(
subscribe). 데이터 생기면 나한테 던져줘(onNext)." - 데이터가 미래의 어느 시점에 도착합니다. (비동기)
2. 리액티브 스트림즈의 4대장 (인터페이스)
이 4가지 인터페이스가 서로 대화를 주고받으며 데이터를 처리합니다.
- Publisher (생산자): 데이터를 만들어내는 녀석입니다. (예: DB, 외부 API)
subscribe(Subscriber s): "구독자, 들어와!"
- Subscriber (소비자): 데이터를 받아서 처리하는 녀석입니다. (예: 우리 서버, 클라이언트)
onSubscribe(Subscription s): "구독 시작됐다!"onNext(T t): "데이터 하나 도착!"onError(Throwable t): "에러 발생!"onComplete(): "데이터 다 보냈어. 끝!"
- Subscription (구독권): 생산자와 소비자 사이의 연결 고리이자 리모컨입니다.
request(long n): "n개만 더 줘." (★ 핵심)cancel(): "구독 취소할래."
- Processor (중개자): 생산자와 소비자 사이에서 데이터를 가공하는 녀석입니다. (Publisher이자 동시에 Subscriber)
3. 백프레셔(Backpressure): "체할 것 같으니까 천천히 줘!"
리액티브 스트림즈가 탄생한 진짜 이유는 바로 Backpressure(배압) 때문입니다.
😱 문제 상황: Push 모델의 비극
생산자(Publisher)는 초당 10,000개의 데이터를 뿜어냅니다.
그런데 소비자(Subscriber)는 1초에 100개밖에 처리를 못 합니다.
-> 소비자의 메모리 큐(Queue)에 데이터가 계속 쌓이다가... OutOfMemoryError 펑! 서버가 죽습니다.
😎 해결책: Pull 모델의 도입 (Backpressure)
소비자가 생산자에게 이렇게 말합니다.
"나 지금 바쁘니까 딱 10개만 줘(request(10)). 다 처리하면 더 달라고 할게."
이것이 바로 백프레셔입니다. 소비자가 감당할 수 있는 만큼만 데이터를 요청해서 시스템의 안정성을 보장하는 기술이죠.
4. 코드 흐름으로 이해하기
말로만 하면 어려우니, 실제 동작 흐름을 의사 코드(Pseudo-code)로 볼까요?
// 1. 소비자가 구독을 요청합니다.
publisher.subscribe(subscriber);
// 2. 생산자가 구독권(Subscription)을 줍니다.
// [Subscriber 내부]
public void onSubscribe(Subscription s) {
this.subscription = s;
// ★ 핵심: "일단 1개만 줘봐." (Backpressure)
s.request(1);
}
// 3. 생산자가 데이터를 1개 보냅니다.
// [Subscriber 내부]
public void onNext(Data data) {
System.out.println("데이터 처리: " + data);
// 처리 끝났으니 1개 더 줘!
this.subscription.request(1);
}
이렇게 하면 생산자가 아무리 빨라도, 소비자가 request()를 하지 않으면 데이터를 보내지 않기 때문에 서버가 터질 일이 없습니다. 시스템의 회복 탄력성(Resilience)이 엄청나게 좋아집니다.
5. WebFlux와의 관계
Spring WebFlux는 이 Reactive Streams 표준을 구현한 Project Reactor라는 라이브러리를 기반으로 만들어졌습니다.
- WebFlux에서는 저 복잡한
Subscription,request()코드를 직접 짤 필요가 없습니다. - Mono와 Flux라는 아주 편리한 도구가 다 알아서 해주거든요.
우리는 그저 "데이터가 흐른다", "소비자가 속도를 조절한다"는 개념만 머릿속에 넣으면 됩니다.
마치며
오늘의 결론입니다.
- Reactive Streams는 데이터를 한 번에 받지 않고 흐름(Stream)으로 처리하는 표준이다.
- Publisher(생산자)가 데이터를 주고, Subscriber(소비자)가 받는다.
- Backpressure는 소비자가 "나 처리할 수 있는 만큼만 줘!"라고 요청해서 시스템 과부하를 막는 핵심 기술이다.
개념은 잡혔는데, "그래서 자바 코드로 어떻게 짜는데?"라는 의문이 드시죠? List 대신 뭘 써야 할까요?
다음 포스팅에서는 WebFlux의 양대 산맥, 01개의 데이터를 다루는 N개의 데이터를 다루는 Mono와 0Flux에 대해 알아보며 본격적인 코딩을 시작해 보겠습니다.
도움이 되셨다면 좋아요와 댓글 부탁드립니다! 😊
'IT > SpringBoot' 카테고리의 다른 글
| [Reactor] "map과 flatMap, 도대체 뭐가 다른가요?" 마법의 연산자 정복하기 (0) | 2026.04.01 |
|---|---|
| [Reactor] "List랑 뭐가 달라요?" Mono와 Flux, 0개 1개 그리고 N개 (0) | 2026.03.31 |
| [Spring WebFlux] "MVC랑 뭐가 달라요?" 블로킹(Blocking) vs 논블로킹(Non-Blocking) 완벽 이해 (0) | 2026.03.30 |
| [Spring Boot] "새로고침 없이 알림이 오네요?" WebSocket과 STOMP로 실시간 채팅방 만들기 (0) | 2026.03.30 |
| [Spring Boot] "내 서버는 몇 명까지 버틸까?" nGrinder로 부하 테스트(Load Test) 하고 병목 지점 찾기 (0) | 2026.03.29 |
