Netty
- https://github.com/netty/netty/wiki/User-guide-for-4.x
- https://netty.io/wiki/user-guide-for-4.x.html
- 공식 docs가 최고야!
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}
- 스레드 이름은
- Tomcat 등 Servlet 3.1+ container
- SpringBoot의 WebFlux starter는 Netty를 기본 서버로 사용하고 있음.
starter-web
과starter-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 * availableProcessors
개EventLoop
로 이루어져 있다. (= 멀티 스레드)
- The first one, often called ‘boss’, accepts an incoming connection.
- 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를 코루틴 등으로 래핑해서 비동기처럼 만들어 쓰는 방법도 같은 맥락에서 사용할 수 있다.
- 뒤쪽에 EventLoop를 하나 더 만들어서 Blocking job을 여기에 던지는 식으로 처리하는게 한 가지 대안이 될 수 있다.
- Persistence API가 Blocking이면 그 앞단에서 Worker Group을 쓴다고 해도, 결국 워커의 수 보다 더 많은 요청이 들어오는 경우 모든 워커가 응답을 대기하며 Blocking에 빠질 수 있다.
This post is licensed under CC BY 4.0 by the author.