spring mvc와 webflux에 대한 비교를 해보겠습니다.
reactive stack은 spring boot2 버전부터 지원되고 있습니다.
Reactive Stack
Reactive Stack은 비동기적이고 논블로킹 방식으로 작동하는 스택입니다. Spring WebFlux는 이 스택의 중심에 있으며, Reactive Streams API와 Reactor 라이브러리를 기반으로 구축되었습니다. Reactive Stack은 다음과 같은 특징을 가지고 있습니다:
- 논블로킹 I/O: 여러 요청을 병렬적으로 처리할 수 있어, 대규모 트래픽 처리에 적합합니다.
- 멀티코어 프로세서 활용: 다중 코어를 효과적으로 사용하여 고성능을 달성할 수 있습니다.
- Netty 및 Servlet 3.1+와 같은 비동기 컨테이너에서 실행되며, 동시성 처리가 중요한 서비스에서 뛰어난 성능을 제공합니다.
- Reactive Streams Adapters와 같은 리액티브 방식으로 데이터를 처리하는 컴포넌트들을 지원합니다.
- Spring Security Reactive와 Spring Data Reactive Repositories를 통해 보안과 데이터 저장소도 비동기적으로 처리할 수 있습니다. 예를 들어, MongoDB, Cassandra, Redis, Couchbase, R2DBC와 같은 데이터베이스를 비동기적으로 처리할 수 있습니다.
Servlet Stack
Servlet Stack은 전통적인 동기 방식의 블로킹 I/O를 사용하는 스택으로, Spring MVC를 중심으로 설계되었습니다. 이 스택은 다음과 같은 특징을 가지고 있습니다:
- 동기적 블로킹 I/O: 요청과 응답이 한 번에 하나씩 처리되며, 각 요청은 하나의 스레드에서 실행됩니다.
- Servlet Containers에서 실행되며, Servlet API를 기반으로 구축된 전통적인 아키텍처입니다.
- Spring Security 및 Spring MVC를 활용하여 보안 및 요청 처리 작업을 수행합니다.
- Spring Data Repositories는 JDBC, JPA, NoSQL과 같은 동기적 데이터 저장소 인터페이스를 지원합니다.
요약
- Reactive Stack은 비동기, 논블로킹 방식으로 대규모 동시성 처리를 필요로 하는 환경에서 최적의 성능을 발휘합니다. I/O 중심의 작업이 많은 애플리케이션에 적합합니다.
- Servlet Stack은 동기적 블로킹 I/O로 전통적인 요청-응답 처리 방식에 더 적합합니다. CPU 중심의 연산이 많은 작업이나 흐름 제어가 중요한 애플리케이션에 적합합니다.
Reactor란?
Reactor는 리액티브 프로그래밍을 위한 Java 라이브러리로, 비동기 및 논블로킹 방식으로 데이터를 처리하기 위해 사용됩니다. Spring WebFlux는 바로 이 Reactor를 기반으로 구축되었으며, Reactive Streams 사양을 따릅니다. Reactor는 Spring 생태계에서 리액티브 기능을 제공하는 핵심 라이브러리로서, 대규모 동시성 처리 및 고성능을 필요로 하는 애플리케이션에 매우 유용합니다.
Reactor의 주요 개념
1. Mono와 Flux:
- Mono: 0 또는 1개의 요소를 비동기적으로 처리할 때 사용합니다. 예를 들어, HTTP 요청에 대한 단일 응답을 처리할 때 Mono를 사용합니다.
- Flux: 0 또는 N개의 요소를 처리하는 스트림입니다. 데이터를 스트리밍하거나 다수의 비동기 이벤트를 처리할 때 사용됩니다.
2. 논블로킹 I/O:
- Reactor는 데이터를 비동기적으로 처리하며, I/O 작업이 완료될 때까지 다른 작업을 계속 진행할 수 있어 자원을 효율적으로 사용할 수 있습니다. 이 덕분에 대규모 트래픽과 동시성을 처리하는 애플리케이션에서 높은 성능을 발휘합니다.
3. 백프레셔(Backpressure):
- Reactor는 Reactive Streams 사양을 따르며, 백프레셔 기능을 제공합니다. 이는 데이터 소비 속도가 생산 속도를 따라가지 못할 때, 소비자가 시스템에 신호를 보내 과부하를 방지하는 메커니즘입니다. 이를 통해 시스템이 데이터 흐름을 제어하고, 안정적인 퍼포먼스를 유지할 수 있습니다.
4. 리액티브 프로그래밍:
- Reactor는 리액티브 프로그래밍을 지원하여 비동기 데이터 스트림을 선언적으로 정의하고, 이벤트 기반으로 데이터를 처리합니다. 이를 통해 반응형(reactive) 방식으로 시스템이 이벤트에 유연하게 반응할 수 있도록 합니다.
Reactor와 Spring WebFlux의 관계
Spring WebFlux는 Reactor를 기반으로 동작합니다. WebFlux는 Reactor의 Mono와 Flux를 사용해 비동기 처리 파이프라인을 구성하고, 데이터의 흐름을 제어합니다. 예를 들어, HTTP 요청이 들어오면 WebFlux는 Mono나 Flux를 반환해 응답을 비동기적으로 처리하고, 논블로킹 방식으로 서버의 리소스를 효율적으로 사용합니다.
요약
Reactor는 Spring WebFlux에서 리액티브 프로그래밍을 구현하기 위한 핵심 라이브러리로, 비동기 및 논블로킹 처리의 기반이 됩니다. 이를 통해 대규모 동시성 처리가 필요한 애플리케이션에서 효율적인 리소스 관리와 고성능을 보장할 수 있습니다.
Servlet tomcat
클라이언트의 HTTP 요청을 Queue에 넣게 됩니다. 그리고 Thread Pool에 요청에 대한 응답을 위한 미리 만들어진 쓰레드를 꺼내다 쓰게 됩니다. 너무 많은 요청이 오게 되면 쓰레드풀에서 쓰레드가 모두 사용되게 됩니다. 그리고 Queue까지 가득 차게 되면 더이상 처리하지 못하게 되므로 HTTP Request는 실패처리하게 됩니다.
요청 처리가 어떻게 이루어지는지 더 세분화하여 살펴 보겠습니다.
클라이언트가 Request를 하게 되면 Servlet을 거쳐 Spring container로 부터 비즈니스 로직을 처리하게 됩니다. 그리고 동기적으로 DB까지 요청되는 흐름이 하나의 흐름으로 지나가게 됩니다.
이렇게 하나의 쓰레드에서 순차적으로 일련의 과정으로 진행되는 것은 문제 파악과 흐름을 이해하는 것이 직관적이며 장점이 됩니다.
Blocking I/O로 운영되므로 만약 DB로 요청된 응답이 늦게 도달한다면 요청 대기 상태에 빠집니다. 그러면 HTTP Requst에 대한 Response역시 지연됩니다. 이로 인해 Thread Pool에 대한 쓰레드 반납과 앞선 이미지의 Tomcat의 Queue역시 가득차게 되면 결국 요청 오류가 발생합니다.
결국 대량의 I/O가 발생하면 그에 맞는 Thread 관리 전략이 필요하므로 이점에 유의해야 합니다.
Reactive Stack
Netty는 비동기 이벤트 기반 네트워크 애플리케이션 프레임워크로, 주로 고성능 네트워크 서버와 클라이언트를 개발하는 데 사용됩니다. Netty는 자바로 구현된 프레임워크로, 특히 대규모 트래픽을 처리하는 고성능 비동기 I/O 시스템에서 매우 널리 사용됩니다.
Netty의 주요 특징
1. 비동기 및 논블로킹 I/O:
- Netty는 NIO (Non-blocking I/O)를 기반으로 설계되어, 대규모의 네트워크 트래픽을 처리할 때 매우 효율적입니다. 각 요청이 대기하는 동안 스레드를 차단하지 않기 때문에, 더 적은 리소스로 더 많은 동시 요청을 처리할 수 있습니다.
2. 이벤트 기반 아키텍처:
- Netty는 이벤트 기반(event-driven)으로 동작하여, 특정 이벤트(데이터 수신, 연결 해제 등)에 대해 이벤트 핸들러가 호출됩니다. 이를 통해 코드가 간결해지고, 비동기적 작업을 쉽게 처리할 수 있습니다.
3. 확장성 및 고성능:
- Netty는 수십만 개의 동시 연결을 처리할 수 있을 정도로 확장성이 뛰어납니다. CPU와 메모리를 효율적으로 사용하며, 특히 I/O Bound 작업에서 강력한 성능을 발휘합니다.
4. 유연한 프로토콜 지원:
- Netty는 다양한 네트워크 프로토콜을 쉽게 구현할 수 있는 프레임워크를 제공합니다. HTTP, WebSocket, TCP/IP, UDP 등 다양한 프로토콜을 지원하며, 커스텀 프로토콜을 쉽게 개발할 수 있습니다.
5. 다중 플랫폼 지원:
- Netty는 다양한 플랫폼과 운영 체제에서 동작할 수 있는 유연성을 가지고 있습니다. 특히, Linux에서는 epoll과 같은 고성능 네트워크 I/O 기법을 사용할 수 있어 성능이 더욱 향상됩니다.
Netty 요청 처리 방식과 내부 구조
단일 스레드 이벤트 루프 기반 구조
- Event Queue
• 클라이언트로부터 동시 요청이 들어오면, 이 요청들은 Event Queue에 쌓입니다. - Event Loop (Single Thread)
• Event Loop는 단일 스레드로 실행되며, Event Queue에 쌓인 요청들을 하나씩 처리합니다.
• 이 과정에서 논블로킹 I/O 방식으로 동작하며, 하나의 요청이 처리되는 동안 다른 요청의 처리를 차단하지 않습니다 - Handler
• Event Loop는 각각의 요청을 Handler로 전달합니다. 이 핸들러는 실제 요청을 처리하는 로직을 포함하고 있습니다.
이 구조는 단일 스레드로 동작하지만 비동기적으로 요청을 처리하기 때문에 많은 동시 요청을 효율적으로 처리할 수 있습니다.
Netty의 Boss와 Worker 이벤트 루프 그룹
- Client
• 클라이언트가 서버로 요청을 보내며, 이 요청은 여러 연결로 서버에 전달됩니다. - Boss Event Loop Group
• Acceptor 역할을 수행하는 Boss 그룹은 클라이언트로부터 연결을 받아들이고, 실제 데이터 처리를 위해 Worker Event Loop Group에 이 요청을 전달합니다.
• Boss는 주로 연결 수락만을 담당하고, I/O 처리는 하지 않습니다. - Worker Event Loop Group
• Worker는 실질적으로 클라이언트의 요청을 처리하는 그룹입니다. 여러 개의 Event Loop로 구성되어 있으며, 각 Event Loop는 클라이언트 요청을 비동기적으로 처리합니다.
이 구조는 클라이언트 요청을 두 가지로 나누어 처리하며, 연결 관리와 실제 데이터 처리 역할을 분리하여 효율적인 비동기 I/O 처리가 가능합니다.
Event Loop와 Channel, Multiplexing
- Event Loop
• Event Loop는 논블로킹 I/O를 사용하여, 동시에 여러 클라이언트의 요청을 처리합니다. - Channel
• Channel은 각 클라이언트의 네트워크 연결을 관리하는 객체입니다. 각 Event Loop는 여러 Channel을 처리하며, 이를 통해 여러 클라이언트의 요청을 동시에 처리할 수 있습니다. - Multiplexing
• 하나의 Event Loop가 여러 Channel을 동시에 관리하는 방식입니다. 이를 통해 높은 동시성을 지원합니다.
이 구조는 Netty의 비동기, 논블로킹 방식의 핵심으로, 하나의 Event Loop가 다수의 클라이언트 요청을 처리할 수 있습니다.
Channel Pipeline과 Handler
- Channel
• Channel은 클라이언트와 서버 간의 데이터를 주고받는 통로입니다. - Channel Handler
• Channel을 통해 들어온 데이터를 처리하는 여러 핸들러들이 연결되어 있습니다. 이 핸들러들은 파이프라인을 형성하여 순차적으로 데이터를 처리합니다.
• 예시로는 HTTP 요청을 처리하는 http codec과 사용자 정의 핸들러인 Custom handler가 있습니다.
이 파이프라인 구조는 Netty의 유연한 데이터 처리 방식을 보여주며, 각 단계에서 데이터를 가공하거나 처리할 수 있습니다.
Spring WebFlux와 Netty의 통합 구조
- Client
• 클라이언트가 서버로 요청을 보냅니다. - Netty
• Netty는 비동기적으로 클라이언트 요청을 받아들여 Controller/Service로 전달합니다. - Controller/Service
• 비즈니스 로직을 처리하는 곳으로, Netty로부터 받은 요청을 처리하고, 데이터베이스 또는 다른 서비스에 접근하여 데이터를 가져옵니다. - Reactor
• 이 구조에서는 Reactor 패턴이 사용되며, 이는 Netty의 비동기 논블로킹 I/O 방식을 기반으로 동작합니다. 이를 통해 높은 동시성과 성능을 제공합니다.
Netty와 Spring WebFlux가 어떻게 비동기, 논블로킹 방식으로 클라이언트의 요청을 처리하는지를 보여줍니다. 주요 개념은 이벤트 루프, 채널, 핸들러, 파이프라인 처리 및 Reactor 패턴을 통한 비동기 처리입니다. 이를 통해 Spring WebFlux와 Netty는 높은 성능과 확장성을 제공하는 비동기 웹 애플리케이션을 구현할 수 있습니다.
Netty의 사용 사례
1. 고성능 웹 서버:
- Netty는 대규모 트래픽을 처리할 수 있는 고성능 웹 서버의 기반으로 사용됩니다. 대표적인 사례로는 Netty를 기반으로 한 웹 프레임워크인 Spring WebFlux에서 사용됩니다.
2. 마이크로서비스 통신:
- Netty는 비동기 통신에 최적화되어 있어, 마이크로서비스 간 통신에도 널리 사용됩니다. 특히 gRPC, WebSocket 등에서 Netty를 활용하여 효율적인 네트워크 통신을 처리할 수 있습니다.
3. 게임 서버:
- Netty는 실시간 처리가 중요한 온라인 게임 서버에서도 자주 사용됩니다. 대규모 유저의 동시 접속과 데이터를 비동기적으로 처리하는 데 매우 적합합니다.
4. 프록시 서버 및 게이트웨이:
- Netty는 프록시 서버나 API 게이트웨이에서 중간 네트워크 처리 역할을 하는 데 적합합니다. 비동기 I/O 성능 덕분에 많은 요청을 효율적으로 처리할 수 있습니다.
요약
Netty는 비동기적 네트워크 프로그래밍을 위한 강력한 프레임워크로, 대규모 네트워크 트래픽을 처리하는 고성능 서버와 클라이언트를 구축하는 데 적합합니다. 특히 비동기와 논블로킹 I/O를 통해 높은 동시성을 처리할 수 있으며, HTTP, WebSocket, TCP/IP 등 다양한 네트워크 프로토콜을 지원하는 유연한 아키텍처로 널리 활용됩니다.
'프레임워크 > 자바 스프링' 카테고리의 다른 글
Spring Webflux 실습 - 1 (1) | 2024.09.25 |
---|---|
Webflux - reactor (0) | 2024.09.18 |
Webflux 소개 (0) | 2024.09.17 |
접속자 대기열 시스템 #1: 시스템 설계와 Spring WebFlux, Redis (3) | 2024.09.09 |
대규모 트래픽 게시판 구축 시리즈 #14: 배포 자동화 (1) | 2024.09.07 |