Netty와 Spring Webflux
서버개발

Netty와 Spring Webflux

Netty란

비동기 이벤트 기반 네트워크 응용프로그램 프레임워크이다.
단순히 네트워크 통신과 관련된 기능 뿐만이 아니라 여러 네트워크 어플리케이션에서의 기능도 제공하고 있어 서버 개발자들이 자신의 비즈니스 로직에 더 집중할 수 있도록 할 수 있다.
 
 
 
 

Netty 프레임워크의 특징

비동기 입출력
Netty 프레임워크는 비동기 처리를 지향한다. 요청을 보낸 뒤 즉시 반환한 다음 다른 작업을 하다 요청한 작업의 처리가 완료되면 나중에 응답 받는 방식이다. 보낸 요청의 응답이 올 때까지 기다리는 동기와 상반된 방식
 
Blocking & Non Blocking Socket

read, write, accept 등의 메서드가 호출되면 완료될 떄까지 쓰레드가 멈추는 블로킹 방식과 하나의 스레드로 여러 클라이언트를 대응하는 논 블로킹 소켓을 모두 지원한다.
 
Blocking I/O, Non Blocking I/O처럼 HTTP 방식을 소켓에 적용한 모델로 Netty는 추상화 방식을 지원하기 때문에 소켓 모드를 바꾸어도 데이터 송수신 부분의 로직을 변경하지 않도록 작성할 수 있다.
 
Tomcat과의 차이
둘 다 웹 어플리케이션 기반의 서버이지만 차이점이 존재한다.

  1. 아키텍처Netty는 이벤트 기반의 비동기 네트워크 프레임워크로 클라이언트의 요청을 비동기로 처리하여 적은 스레드로 높은 성능을 제공한다.
    Tomcat은 전통적인 서블릿 기반의 웹 어플리케이션 서버(WAS)로, 클라이언트 요청을 처리하기 위해 스레드 풀을 사용한다.

  2. 성능Netty는 비동기 방식의 클라이언트 요청을 처리하기 위해 멀티 코어를 활용하여 수십만 개의 동시 연결을 처리할 수 있다.
    Tomcat은 대규모 웹 어플리케이션을 처리하기 최적화되어 있어 일반적으로 단일 코어로 수천 개의 동시 연결을 처리 가능하다.

  3. 유연성Netty는 더 적은 기능을 제공하지만, 모듈식 아키텍처를 사용해 개발자가 필요한 기능만 사용할 수 있다. HTTP 뿐만 아니라 다양한 프로토콜을 지원하여 유연성이 높다.
    Tomcat은 Java EE 표준에 따라 작동하며 추가적인 확장이나 커스터마이징이 어려울 수 있다.

Event Model
입출력을 위해 정의된 이벤트 모델이 존재한다.
코어 로직을 수정하지 않고도 직접 이벤트 타입을 구현할 수 있도록 지원하며, 각 이벤트 타입은 계층화되어 있어 구분된다.
Channel Event는 Channel Handlers에 의해 ChannelPipeline에서 처리된다.
이벤트의 주체는 소켓이며 데이터를 소켓에 전달하기 위해 데이터 핸들러를 이용한다.
로직 분리와 코드의 재사용성 증가, 에러 처리 부담 완화에 도움이 된다.

  • InBoundEvent(데이터 수신)
    클라이언트로부터 데이터 수신 시 발생하는 이벤트에 관심이 있으면 데이터 수신 이벤트를 담당하는 메서드에 원하는 로직을 넣으면 된다
  • OutBoundEvent(데이터 송신)

Universal Asynchoronous I/O API
TCP, UDP에 따라 다른 형태의 API를 제공한다.
TCP 어플리케이션을 UDP로 포팅하는 것은 많은 공수가 필요로 하는데 Netty의 Channel이라는 Async I/O 인터페이스를 이용하여 Point to Point 통신을 추상화 할 수 있다.
그렇기 때문에 실제 통신 부분과 상관없이 로직을 개발하여 추후에 통신 방식이 변경되더라도 쉽게 변경할 수 있도록 지원한다.
 
ChannelBuffer
독자적인 ByteBuffer가 구현이 되어있어 제로카피와 빠른 성능, 다이나믹 버퍼 타입을 지원한다.
 
ETC
네트워크 프로그래밍에서는 비즈니스 로직과 프로토콜 코덱을 분리하는게 좋다.
HTTP, SSL, Protocol Buffer도 지원한다
 
 
 
 

Spring Webflux

Spring 5에서 새롭게 추가된 모듈로, 클라이언트와 서버에서 reactive 스타일의 어플리케이션을 도와주는 모듈이다.
spring과 완벽한 통합을 이루고 netty를 지원하며, 비동기 논 블로킹 메시지 처리를 도와준다.

SpringMVC란?
웹 계층의 서블릿 API를 기반으로 클라이언트의 요청을 처리하는 모듈 개발 영역을 MVC(Model-View-Controller)로 구분하여 각 역할에 맞게 코드를 작성하는 개발 방식
MVC 패턴을 도입하면서 UI 영역과 도메인(비즈니스 로직) 영역이 구분되어 서로에게 영향을 주지 않으면서 개발과 유지보수를 가능한 방향으로 설계하였다.

  • Model
    Spring MVC 기반의 웹 어플리케이션이 클라이언트의 요청을 전달받으면 요청 사항을 처리하기 위한 작업
    처리한 작업의 결과 데이터를 클라이언트에게 응답을 돌려주어야 하는데, 클라이언트에게 응답으로 돌려주는 작업의 처리 결과 데이터를 Model이라고 칭한다.

    클라이언트의 요청을 구체적으로 처리하는 영역을 서비스 계층이라 하며, 요청 사항을 처리하기 위해 Java 코드로 구현한 것을 비즈니스 로직이라고 한다.
  • View
    Model을 이용하여 웹 브라우저와 같은 애플리케이션의 화면에 보이는 리소스를 제공하는 역할
    HTML 페이지 등을 출력하는 것 뿐만이 아닌 PDF, Excel 등의 문서 형태 출력 그리고 자주 사용되는 XML, JSON 등 특정 형식의 포맷 변환까지 View가 담당한다.
  • Controller
    클라이언트 측의 요청을 직접적으로 전달받는 엔드포인트로 Model과 View의 중간에서 상호작용을 해주는 역할
    클라이언트의 요청을 전달받아 비즈니스 로직을 거친 후, Model 데이터가 만들어지면 이 Model을 View로 전달하는 역할을 수행한다.

 
Spring MVC의 구조
 

동작 순서

  1. 핸들러 조회 : URL에 매핑된 핸들러(컨트롤러)를 조회
  2. 핸들러 어댑터 조회 : 핸들러를 실행할 수 있는 핸들러 어댑터를 조회
  3. 핸들러 어댑터 실행
  4. 핸들러 실행
  5. ModelAndView 반환 : 핸들러 어댑터는 핸들러가 반환하는 정보를 변환하여 반환
  6. viewResolver 호출 : 뷰의 논리 이름을 물리 이름으로 변경
  7. View 반환 : 렌더링 역할을 담당하는 뷰 객체 반환
  8. View 랜더링 : 뷰를 통해 뷰를 렌더링

공통점
MVC와 Webflux 모두 Spring Framework에서 웹 어플리케이션을 개발하기 위한 프레임워크로 공통적으로 @Controller, Reactive Client이 존재한다.
둘 다 Tomcat, Jetty, Undertow와 같은 서버에서 실행할 수 있다.
 
차이점
Spring MVC에서는 명령형 논리, JDBC, JPA를 가질 수 있다.
그렇기 때문에 어플리케이션이 JPA, JDBC 또는 네트워킹 API에 의존하는 경우 Spring MVC를 사용하면 된다.
 
Spring MVC는 동기적인 방식으로 동작하며, 요청이 발생하면 해당 요청을 처리하기 위해 스레드를 블로킹하여 처리한다. 이 방식은 처리량이 많을 경우 성능이 저하될 수 있다.
 
하지만 Spring Webflux에서는 비동기적인 방식으로 동작하여 요청이 발생하면 해당 요청을 처리하기 위해 블로킹하지 않고, 다른 스레드에게 넘겨 비동기적으로 처리한다. Reactive Programming을 사용하여 개발할 때 매우 유용하다. 기능적 엔드 포인트, 이벤트 루프, 동시성 모델을 가질 수 있으며 Netty 서버에서 실행할 수 있다는 장점이 있다.
 
물론 Spring MVC에서도 비동기적인 방식으로 처리할 수 있다. Servlet 3.0은 Async Servlet 기능을 지원하며, 이를 통해 비동기적인 요청 처리를 할 수 있지만 스펙에 의해 제한되어 있고 기본적으로는 동기적인 방식으로 동작한다.
 
또한, Reactive Streams API를 지원하고 MVC에서도 Netty가 HTTP 라이브러리로 제공되기 때문에 비동기적인 요청 처리를 할 수 있으나, Netty를 직접 사용하여 개발해야 한다. 이는 개발자에게 추가적인 부담이 될 수 있다. 또한, MVC의 경우에는 비동기 요청 처리에 대한 지원이 제한적이기 때문에 높은 처리량이 필요한 서비스나 대규모 트래픽을 다루기에는 한계가 있다.
 
반면에 WebFlux는 Reactive Streams API를 기반으로 구현되어 있어 이를 이용해 높은 처리량과 대규모 트래픽을 다룰 수 있는 비동기 서비스를 쉽게 개발할 수 있다. 이벤트 루프 기반의 Netty 서버에서 동작하여 Netty의 모든 기능을 활용할 수 있고, Spring WebFlux는 비동기 데이터베이스 드라이버, 비동기 HTTP Client, 비동기 메시징 서비스와 같은 외부 시스템과의 통합을 지원하여, 전체적인 비동기 시스템을 구축할 수 있도록 돕는다.
 

MVC는 Servlet을 기반으로 한 모델이고, WebFlux는 Reactive Streams API를 기반으로 한 모델이다.
Servlet은 요청-응답 기반의 동기적인 웹 프로그래밍 모델을 기반으로 하며 클라이언트 요청을 받아 처리하고, 즉시 응답을 반환한다. 이러한 방식은 동기적인 통신 방식이기 때문에 대규모 트래픽이 발생할 경우 성능 문제가 발생할 수 있다. 또한, Thread-per-Request 방식을 일반적으로 사용하기 때문에 많은 클라이언트 요청이 동시에 처리될 경우, 서버의 자원 부족 문제를 야기할 수 있다.
 
반면에 Reactive Streams API는 비동기적인 웹 프로그래밍 모델을 기반하기 때문에 Pub-Sub 패턴을 기반으로 하여 데이터가 생성되는 시점과 데이터가 소비되는 시점을 분리, 비동기적으로 처리할 수 있다. 대규모 트래픽이 발생할 경우 효율적인 리소스 관리와 적은 쓰레드로도 높은 처리량을 보장할 수 있다.
 
이러면 WebFlux에서 Servlet을 사용하지 않는 것인가? 라고 오해할 수 있는데 그렇지 않다. WebFlux는 Servlet을 여전히 중요한 역할로 사용하고 HTTP 요청을 처리하고 응답을 생성한다. 그렇기 때문에 WebFlux는 Servlet과 Reactive Streams API를 함께 사용하여 비동기적인 웹 프로그래밍을 구현한다.
 
 
 
 

마치며

결론적으로, Spring MVC를 사용하는 경우는

  1. 단순한 웹 어플리케이션 개발
  2. 자원이 충분한 환경에서의 사용
  3. 다른 기술과의 연동
  4. Servlet API를 사용하여 구현되어 있기 떄문에 다른 Java 기술과의 연동이 쉽다(JSP,JDBC,JPA)
  5. 코드의 간결함

Spring WebFlux를 사용하는 경우는

  1. 대규모 트래픽 처리 Non-blocking I/O 모델을 사용하여 단일 쓰레드에서 많은 요청을 처리할 수 있다.
  2. 데이터 스트리밍 처리 Reactive Streams API를 기반하여 데이터 스트리밍 처리에 적합하다.
  3. 다양한 데이터 베이스 처리 NoSQL 데이터베이스나 비동기적인 데이터베이스 처리가 필요한 경우 유용하다.
  4. 높은 확장성


    1. Spring MVC와 WebFlux는 모두 Spring Framework 기반으로 만들어진 웹 어플리케이션 프레임워크입니다.

    2. Spring MVC는 Servlet API와 Blocking I/O 모델을 기반으로 하고 있습니다. 반면에, WebFlux는 Reactive Streams API와 Non-Blocking I/O 모델을 기반으로 하고 있습니다.

    3. Spring MVC는 요청당 쓰레드 모델로 동작하며, 블로킹 I/O를 사용합니다. 반면에, WebFlux는 이벤트 루프와 콜백 모델을 사용하여 비동기적으로 요청을 처리합니다.

    4. Spring MVC는 데이터베이스와 같은 블로킹 API를 사용할 수 있습니다. 반면에, WebFlux는 Non-Blocking API를 사용하는 데이터베이스와 함께 사용하는 것을 권장합니다.

    5. Spring MVC는 간단하고 빠르게 구축할 수 있으며, 블로킹 API를 사용하는 서비스에서 적합합니다. 반면에, WebFlux는 높은 동시성과 처리량을 필요로 하는 서비스에서 적합합니다.

    6. Spring MVC는 기존의 Java EE 기반 애플리케이션을 개선하고 싶은 경우에도 적합합니다. 반면에, WebFlux는 Reactive Programming 모델을 사용해야 하기 때문에 비교적 신규 프로젝트나 기존의 Blocking I/O 기반의 애플리케이션을 개선하고 싶은 경우에 적합합니다.