Spring RSocket 마스터 노트 시리즈 1편. RSocket이 HTTP·gRPC·WebSocket의 한계를 어떻게 풀었는지, Reactive Streams 위에서 양방향·다중 통신을 자연스럽게 처리하는 메커니즘, 프레임(Frame) 구조와 헤더 9 종류, TCP·WebSocket·UDP 전송 계층 선택, 백프레셔가 RSocket의 핵심 차별화인 이유까지.
이 글은 Spring RSocket 마스터 노트 시리즈의 첫 번째 편입니다. 마이크로서비스 사이 통신의 기본은 HTTP. 하지만 양방향·스트리밍·낮은 지연이 필요하면 한계. RSocket이 그 답 — Reactive Streams 위에 만든 차세대 프로토콜.
이 시리즈 9편은 기본 개념·4 Interaction Models·Spring 서버/클라이언트·메타데이터·보안·로드 밸런싱·테스트·gRPC/WebSocket 비교까지. 1편의 목표 — 왜 RSocket인지, 프레임이 무엇인지 손에 잡히게.
이 시리즈는 RSocket 공식 문서, Reactor·Spring WebFlux 가이드, Reactive Streams 명세 등 공개 자료를 참고해 한국어 학습 노트로 풀어쓴 자료입니다.
Spring Boot 프로젝트에 spring-boot-starter-rsocket 추가하고 첫 Request-Response를 직접 띄워 보면 흐름이 한 번에 잡혀요. 30분이면 첫 RSocket 통신이 손에 들어옵니다.
처음 RSocket이 어렵게 느껴지는 이유
처음 이 단원이 어렵게 느껴지는 이유는 두 가지예요. 첫째, **"왜 RSocket인가"**가 막연합니다. HTTP·gRPC·WebSocket 다 있는데? 둘째, Reactive Streams·프레임·백프레셔 같은 단어가 한 번에 쏟아집니다.
해결법은 한 가지예요. "RSocket = Reactive 위 양방향 메시징" 한 줄. HTTP는 단방향 요청-응답, WebSocket은 양방향이지만 메시지 의미 없음, gRPC는 강력하지만 Reactive 흐름 X. RSocket = 셋의 장점 합. 이 그림이 잡히면 디테일이 따라옵니다.
통신 프로토콜 비교
| 프로토콜 | 모델 | 백프레셔 | Reactive | 양방향 |
|---|---|---|---|---|
| HTTP/1.1 | 단방향 요청-응답 | X | X | X |
| HTTP/2 | 다중화·스트리밍 | X | 부분 | X |
| WebSocket | 양방향 | X | X | O |
| gRPC | RPC + 4 모드 | 부분 | 부분 | O |
| RSocket | 메시징 + 4 모드 | O | O | O |
여기서 정말 중요한 시험 함정 — RSocket의 결정적 차별화 = 백프레셔. 다른 프로토콜은 클라이언트가 처리 못해도 서버가 계속 보냄. RSocket = 클라이언트 페이스에 자동 맞춤.
4 Interaction Models — RSocket의 핵심
1. Request-Response — HTTP 같음 (1:1)
2. Fire-and-Forget — 응답 없음
3. Request-Stream — 1 요청 → N 응답
4. Channel — 양방향 N:N 스트림
이 4가지가 거의 모든 통신 패턴 커버. 자세한 건 2편.
RSocket 등장 배경
Netflix·Facebook 등이 마이크로서비스에서 부딪힌 문제:
시나리오 — 실시간 스트리밍 + 양방향 + 백프레셔
HTTP/2: 단방향 + 백프레셔 X
gRPC: 양방향 OK but Reactive 어려움
WebSocket: 양방향 OK but 메시지 의미 X
해결 — Reactive Streams 위에 프로토콜 만들기 = RSocket.
오픈 소스화 후 Reactive Foundation 관리. 언어 비종속 (Java·JS·Go·Kotlin·.NET).
RSocket = 메시지 기반
HTTP는 요청-응답. RSocket은 메시지 단위.
Stream A: 요청 1 → 응답 1
→ 응답 2
→ 응답 3 (종료)
Stream B: 요청 1 → 양방향 N:N
↓ ↑ ↓ ↑
메시지 메시지 메시지 메시지
같은 연결에 여러 스트림 동시
여기서 시험 함정이 하나 있어요. RSocket은 단일 연결에 다중 스트림. HTTP/2 multiplexing과 비슷하지만 메시지 의미·백프레셔까지.
프레임(Frame) 구조
RSocket의 데이터 단위.
[Frame Header (6 bytes)]
- Stream ID (4 bytes)
- Frame Type + Flags (2 bytes)
[Frame Payload]
- Metadata (선택)
- Data (실제 페이로드)
Frame Type 9 종류
| Type | 의미 |
|---|---|
| SETUP | 연결 시작 (한 번) |
| REQUEST_RESPONSE | 1:1 요청 |
| REQUEST_FNF | Fire-and-Forget |
| REQUEST_STREAM | 1:N 요청 |
| REQUEST_CHANNEL | N:N 요청 |
| PAYLOAD | 실제 데이터 |
| REQUEST_N | 백프레셔 (N개 더 보내라) |
| CANCEL | 스트림 취소 |
| ERROR | 에러 |
| KEEPALIVE | 연결 유지 |
여기서 정말 중요한 시험 함정 — REQUEST_N 프레임이 백프레셔의 핵심. 클라이언트가 "N개 더 보내" 명시. 서버는 그만큼만 전송. 자연스러운 흐름 제어.
전송 계층 — Transport
RSocket은 프로토콜 정의만, 전송은 별개.
| Transport | 용도 |
|---|---|
| TCP | 일반 마이크로서비스 (가장 일반적) |
| WebSocket | 브라우저·방화벽 환경 |
| UDP / Aeron | 초저지연 (HFT 등) |
| HTTP/2 | 일부 환경 |
Spring Boot 기본 = TCP·WebSocket.
백프레셔 — 자연스러운 흐름 제어
Server: REQUEST_STREAM 받음 → 100,000 항목 보내야
Client: 처리 느림 (DB 저장 등)
전통 (HTTP/2):
Server → 메시지 1, 2, 3, ..., 1000 빠르게 보냄
Client 메모리 폭주 → OOM
RSocket:
Client → REQUEST_N(10) "10개 보내"
Server → 메시지 1~10 보내고 멈춤
Client → 처리 완료, REQUEST_N(10) "10개 더"
Server → 메시지 11~20
...
자연스러운 페이스 매칭. Reactive Streams의 spec 그대로 구현.
SETUP 프레임 — 연결 시작
Client → SETUP {
keepalive: 20s, # 핑 간격
lifetime: 90s, # 연결 만료
metadata-mime-type: 'application/json',
data-mime-type: 'application/json',
resume-token: ...,
setup-payload: ... # 인증 정보 등
}
연결 한 번. 이후 모든 통신은 같은 연결 위.
여기서 시험 함정이 하나 있어요. SETUP은 한 번만. 인증 정보·메타데이터 형식 등 한 번 결정. 이후 변경 X.
Resumability — 연결 복구
Client ↔ Server
네트워크 끊김
↓
Resume Token으로 재연결
↓
끊어진 시점부터 이어서
장기 연결 환경 (모바일·IoT)에 유용.
Spring Boot 의존성
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-rsocket'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}
Spring Boot 자동 구성:
RSocketStrategiesRSocketRequester.BuilderRSocketServer(서버 측)
가장 단순한 예시
서버
@Controller
public class GreetingController {
@MessageMapping("greet")
public Mono<String> greet(String name) {
return Mono.just("Hello, " + name + "!");
}
}
spring:
rsocket:
server:
port: 7000
transport: tcp
클라이언트
RSocketRequester requester = RSocketRequester.builder()
.transport(TcpClientTransport.create("localhost", 7000));
Mono<String> response = requester.route("greet")
.data("Alice")
.retrieveMono(String.class);
response.subscribe(System.out::println);
// "Hello, Alice!"
RSocket 사용 사례
적합
- 마이크로서비스 사이 실시간 통신 (이벤트 스트리밍)
- 양방향 통신 (채팅·알림)
- IoT 디바이스 연결 (장기 + 백프레셔)
- 모바일 앱 (네트워크 변동 + Resumability)
부적합
- 공개 REST API (HTTP가 표준)
- 단순 CRUD (HTTP·gRPC가 단순)
- 브라우저 직접 호출 (WebSocket이 더 친화)
여기서 정말 중요한 시험 함정 — 공개 API = HTTP / 내부 마이크로서비스 + 스트리밍 = RSocket. 둘 결합도 OK. RSocket은 만능 X, 적합한 자리에.
디버깅·관찰
logging:
level:
io.rsocket: DEBUG
Wireshark·Pcap
TCP transport는 일반 패킷 캡처 가능. Frame 분석.
Spring Boot Actuator
management:
endpoints:
web:
exposure:
include: rsocket,metrics
시험 직전 한 번 더 — 자주 헷갈리는 함정 모음
여기까지가 1편의 핵심입니다. 시험 직전 또는 실무에서 헷갈릴 때 다시 펼쳐 볼 수 있게 압축 노트로 마무리할게요.
- RSocket = Reactive Streams 위 양방향 메시징
- HTTP·gRPC·WebSocket 한계 해결
- 결정적 차별화 = 백프레셔 (자연스러운 흐름 제어)
- 4 Interaction Models — Request-Response / Fire-and-Forget / Request-Stream / Channel
- 거의 모든 통신 패턴 커버
- 단일 연결 + 다중 스트림
- 프레임 (Frame) = RSocket 데이터 단위
- 헤더 6 bytes (Stream ID + Type + Flags)
- 9 Frame Types — SETUP·REQUEST_*·PAYLOAD·REQUEST_N·CANCEL·ERROR·KEEPALIVE
REQUEST_N이 백프레셔 핵심 (N개 더 보내)- Transport 분리 — TCP (일반) / WebSocket (브라우저) / UDP·Aeron (초저지연) / HTTP/2
- SETUP = 연결 시작 한 번 (인증·메타데이터·resume token)
- Resumability = 끊어진 후 재연결 + 이어서
- 모바일·IoT 친화
- Spring Boot —
spring-boot-starter-rsocket - 자동 구성 —
RSocketStrategies·RSocketRequester.Builder - 서버 —
@MessageMapping+ Mono/Flux - 클라이언트 —
RSocketRequester+route().data().retrieveMono() - 적합 — 마이크로서비스 + 실시간 + 양방향 + IoT
- 부적합 — 공개 REST·단순 CRUD·브라우저 직접
- HTTP와 결합도 OK
시리즈 다른 편
- 1편 — 기본 개념·프레임 (현재 글)
- 2편 — 4 Interaction Models
- 3편 — Spring RSocket 서버
- 4편 — Spring RSocket 클라이언트
- 5편 — 메타데이터·Composite Metadata
- 6편 — 보안·Spring Security RSocket·TLS
- 7편 — 로드 밸런싱·확장
- 8편 — 테스트
- 9편 — RSocket vs gRPC vs WebSocket
공식 문서: RSocket Specification / Spring RSocket 에서 더 깊이.
다음 글(2편)에서는 4 Interaction Models — Request-Response·Fire-and-Forget·Request-Stream·Channel의 동작과 사용 패턴까지 풀어 갑니다.