Skip to content

webFlux와 netty

Spring MVC는 기본적으로 블럭킹이고 동기방식을 사용한다. 비동기 처리 기능이 스프링 프레임워크 3에서 추가되어 지원된다고 하지만, 서블릿은 응답을 기다리는 동안 pool의 스레드들은 여전히 지연시킬 수 있기 때문에 전체 stack이 reactive 해야 하는 요구를 충족시킬 수 없다.

이러한 요구사항에 맞추어 스프링 프레임워크5에 도입된 대안적인 모듈이 바로 WebFlux이고, 웹 요청을 reactive 하게 다루는 데에 초점이 맞추어져 있다.

기존의 서블릿 기반의 Spring Boot는 Tomcat을 기반으로 동작한다. 반면 Spring Boot WebFlux는 여러 가지를 고를 수 있는데, Default로 Netty를 사용한다. Netty를 사용하는 이유는 tomcat은 요청 당 하나의 스레드가 동작하는 반면, netty는 1개의 이벤트를 받는 스레드와 다수의 worker 스레드로 동작하여 보다 효율적으로 데이터를 처리할 수 있기 때문이다.

image

netty는 channel에서 발생하는 이벤트를 EventLoop가 처리하는 구조로 동작한다. 이벤트 루프란 이벤트를 실행하기 위한 무한루프 스레드를 뜻한다.

위의 이미지와 같이 객체에서 발생한 이벤트는 이벤트 큐에 push 되고 이벤트 루프는 이벤트 큐에 입력된 이벤트가 있을 때 해당 이벤트를 꺼내서 실행한다.

이벤트 루프는 지원하는 스레드의 종류에 따라서 단일 스레드와 다중 이벤트 루프로 나누어지게 된다. 또한 이벤트 루프가 처리한 이벤트의 결과를 돌려주는 방식에 따라 Callback과 Futures 패턴으로 나누어지게 되고, netty는 이 두 가지 패턴을 모두 지원한다.

싱글 스레드

싱글 스레드 이벤트 루프는 말 그대로 이벤트를 처리하는 스레드가 하나인 상태를 이야기 한다. 단일 스레드로 동작하기 때문에 예측 가능한 동작을 보장하고, 이벤트 루프의 구현이 단순하다는 장점이 있다. 하지만 하나의 처리시간이 긴 작업이 들어오면 전체 작업 지연시간이 늘어난다는 단점이 있다. 또한 단일 스레드이기 때문에 멀티 코어 cpu환경에서 cpu자원을 효율적으로 사용할 수 없다.

멀티 스레드

멀티 스레드 이벤트 루프는 이벤트를 처리하는 스레드가 여러 개인 모델이다. 싱글 스레드 이벤트 루프에 비해 프레임워크 구현이 복잡하지만, 스레드들이 이벤트 메서드를 병렬로 수행하기 때문에 멀티 코어 cpu의 자원을 효율적으로 사용할 수 있다. 하지만 여러 이벤트 스레드가 하나의 이벤트 큐에 접근하기 때문에 동시성 문제가 발생할 수 있다. 또한 이벤트들이 병렬로 처리되기 때문에 이벤트의 발생순서와 실행 순서가 일치하지 않다.

Netty에서는 멀티 스레드 이벤트 루프의 단점인 발생 순서와 실행 순서가 일치하지 않는다는 문제를 아래와 같은 방법으로 해결한다.

image

  • Netty의 이벤트는 Channel에서 발생한다.
  • 각각의 이벤트 루프 객체는 개인의 이벤트 큐를 가지고 있다.
  • Netty Channel은 하나의 이벤트 루프에 등록된다.
  • 하나의 이벤트 루프 스레드에는 여러 채널이 등록될 수 있다.

멀티 스레드 이벤트 모델에서 이벤트의 실행 순서가 일치하지 않는 이유는 루프들이 이벤트 큐를 공유하기 때문에 발생하게 된다. 따라서 Netty는 이벤트 큐를 이벤트 루프 스레드의 내부에 둠으로써 실행 순서의 불일치 원인을 제거하게 된다.

즉 이벤트 루프 스레드마다 개인의 이벤트 큐를 가짐으로써, 해당 이벤트를 처리하는 스레드가 지정되어 있기 때문에 공유된 하나의 이벤트 큐에 스레드들이 접근하지 않게 된다.