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이 우선함.

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

[!warning] 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.