Post

Netty

Netty가 무엇인가?

  • Netty is an asynchronous event-driven network application framework.
  • Netty is a NIO client server framework which enables quick and easy development of network applications such as protocol servers and clients.
  • It greatly simplifies and streamlines network programming such as TCP and UDP socket server.
Spring WebFlux와 Netty?
  • Spring WebFlux는 다음 두 가지 타입의 서버를 지원
    • Tomcat 등 Servlet 3.1+ container
      • WebFlux 서버로 쓰려면 non-blocking I/O API를 지원해야 함.
      • Servlet 3.1, Tomcat 8.5 부터는 NIO API를 지원.
        • 그러나 다른 Servlet API는 여전히 동기식, Blocking API라서 애매한 구석이 있음. ( docs )
      • 스레드 이름이 http-nio-8080-exec-{i} 이면, tomcat의 nio thread임
    • Netty 등 non-Servlet runtime
      • 스레드 이름은 reactor-http-nio-{i}
  • SpringBoot의 WebFlux starter는 Netty를 기본 서버로 사용하고 있음.
    • starter-webstarter-webflux 의존성 둘 다 존재하는 경우 Tomcat이 우선함.

Controller 메서드의 반환 타입이 Mono이냐 아니냐는 관계 없음. 기본 서버를 따라감.
즉, Netty가 기본 서버로 설정되어 있는 경우, Controller 반환 타입과 무관하게 항상 Netty EventLoop에서 컨트롤러 메서드가 실행되고 (reactor-http-nio)
Tomcat이 기본 서버로 설정되어 있는 경우, Controller 반환 타입과 무관하게 항상 Servlet thread에서 컨트롤러 메서드가 실행됨 (http-nio-8080-exec)

Netty를 쓰는 경우, 시스템 전체가 비동기가 되어야 함.
Controller 메서드를 실행하는 thread pool은 Worker EventLoopGroup 이기 때문 (2 * availableProcessors 개 스레드로 이루어짐)

EventLoopGroup

  • NioEventLoopGroup is a multithreaded event loop that handles I/O operation.
    • NioEventLoopGroup(nThread) 생성자로 넘긴 nThread 개수 만큼 EventLoop 객체를 만들게 된다. (그래서 EventLoopGroup이다)
    • EventLoop 객체는 1 Thread + 1 Selector + 1 TaskQueue 로 구성된다.
  • server-side application을 구현한다면 두개의 NioEventLoopGroup 가 사용됨.
    • The first one, often called ‘boss’, accepts an incoming connection.
      • 즉 server socket(80포트) 리스닝 하고 있다가 connection 요청 들어오면 accept 한다.
      • accept 해서 생성된 connection은 Worker Group으로 넘긴다.
      • default로 1개 EventLoop로 이루어져 있다. (= 싱글 스레드)
    • The second one, often called ‘worker’, handles the traffic of the accepted connection once the boss accepts the connection and registers the accepted connection to the worker.
      • bossd에서 connection을 받아서, 해당 client socket 리스닝 하고 있다가 데이터가 들어오면 read 처리하고, 응답으로 나갈 데이터 write 한다.
      • default로 2 * availableProcessorsEventLoop로 이루어져 있다. (= 멀티 스레드)

  • https://mark-kim.blog/netty_deepdive_1/ 잘 정리되어 있어 참고.

Persistence Layer가 블로킹이면 어떻게?

  • https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-framework-choice
  • 위 공식 링크 보면 나온다.
  • Persistence API가 JPA, JDBC같은 Blocking API이면 일단 Spring MVC가 Best Choice라고 함.
  • 그러나 Reactive로 차근히 전환하고 싶은 상황이라면?
    • Persistence API가 Blocking이면 그 앞단에서 Worker Group을 쓴다고 해도, 결국 워커의 수 보다 더 많은 요청이 들어오는 경우 모든 워커가 응답을 대기하며 Blocking에 빠질 수 있다.
      • 이렇게 되면 기존 스레드 기반 모델보다 성능이 더 안좋을 수도 있다.
    • 그래서, 모든 워커스레드가 블로킹에 빠지지 않도록 뭔가 조치를 취해야 한다.
      • 뒤쪽에 EventLoop를 하나 더 만들어서 Blocking job을 여기에 던지는 식으로 처리하는게 한 가지 대안이 될 수 있다.
        • gRPC가 이런 방법을 사용한다.
      • Persistence API를 코루틴 등으로 래핑해서 비동기처럼 만들어 쓰는 방법도 같은 맥락에서 사용할 수 있다.

gRPC는 내부적으로 이렇게 쓰고 있다.

This post is licensed under CC BY 4.0 by the author.