- Servlet의 변화
Servlet 3.0에서 Async Servlet(비동기 서블릿) 개념 도입
=> 사용자의 요청을 받는 스레드(servlet thread)와 작업을 수행하는 스레드(worker thread)를분리할 수 있게 되었다Servlet 3.1부터는 Non-Blocking I/O가 가능해졌다
=>request 및 response를 처리하는 I/O를Non-Blocking으로 수행- 즉, Servlet의 변화로
SpringMVC에서thread-per-request방식인 기존 로직을비동기 / Non-Blocking으로개선할 수 있게 되었다
- Blocking I/O를 통한 한계
Servlet의 API/Data Access/추가 라이브러리등 에서 결국Blocking I/O가 수행
=> 100% 완전한비동기 / Non-Blocking을 위한 새로운 Stack 개발의 필요성
=>WebFlux라는 이름을 가진 Spring의Reactive-Stack의 등장
- Spring의 reactive-stack web framework
- Srpring5에서 새롭게 추가된 모듈
- Reactive library로 Project Reactor를 채택
- 기본으로
NettyWAS 사용 =>Event-Loop라우팅/핸들링과정을 모두함수형 엔드포인트로 사용 가능Servlet 3.1+의비동기 / non-blocking IO사용- Servlet의
HttpServletReqeust/HttpServletResponse
=>ServerRequest/ServerResponse로 대체
- 완벽한 Reactive-Stack을 통한
비동기 / non-blocking개발적은 양의 스레드와 최소한의 하드웨어 자원으로 효율적인 동시성 핸들링(Concurrent Handling) 을 하는 것
=> How ?
- Request를
Event-Driven방식으로 처리비동기/non-blocking I/O사용
- Servlet의 변화에 따른 thread model의 변화
- Servlet 3.0 미만 :
동기 / 블록킹- Servlet 3.0 :
비동기 / 블록킹- Servlet 3.1+ :
비동기 / 논블록킹
(상세 Task 처리에는Bloacking이 존재할 수 있음)
[ Servlet 3.0 미만 ]
(ref :https://www.youtube.com/watch?v=I0zMm6wIbRI&t=721s)
- 특징
- 사용자의 요청마다 스레드가 필요한
Thread per request방식 (동기 / 블록킹)
=> 보다 효율적인 사용을 위해 스레드 풀(thread pool) 사용- 스레드 풀의 스레드 수 이상의 요청이 오면
Blocking Queue에서 대기
(Queue도 가득차면 오류 발생)
=> 동시성을 위한 대안으로, 단순히 스레드를 늘릴 수는 있다
=> 하지만, 무한정 늘릴수는 없다
- 늘어난 스레드로 인한 많은 문맥교환(
Context Switching) 비용과 메모리, CPU 부하 발생 위험 때문
[ 비동기 서블릿 - Servlet3.0 / 3.1 ]
- Servlet 3.0
- 최초 비동기 서블릿(
Async Servlet)의 등장- 작업을
별도의 스레드에서 수행할 수 있게 되었다
=> 요청을 받는Servlet Thread와, 처리하는Worker Thread로 분리
(tomcat의 thread는servlet thread를 의미)- 즉,
비동기 / 블록킹방식의thread model을 가지게 됨
=>servlet thread는worker thread가 작업을 수행하는 동안Blocking
(ref : https://www.youtube.com/watch?v=aSTuQiPB4Ns)
- Servlet 3.1
Non-Blocking I/O를 지원하게 되면서 더이상servlet thread가 기다리지 X
=>servlet thread는 요청을worker thread에게 할당 후 풀에 반납
=>worker thread의 작업이 끝나면 다시servlet thread를 할당받아response수행
=>비동기 / 논블록킹방식
- 한계
- 사용자의 요청을 받고, 전체 Task 처리를 할당 측면에서는
비동기 / 논블록킹이 되었다- 하지만, 처리되는 세부적인 Task(
DB access,api call) 내에서Blocking API가 호출되면 결국thread는Blocking된다- 즉, 완벽한
비동기 / 논블록킹의 로직을 만들기 위해서는Blocking API가 없어야 한다는 것을 알 수 있다
=>WebFlux의 등장 배경
[ Servlet 3.2 - DeferredResult ]
(ref : https://www.youtube.com/watch?v=aSTuQiPB4Ns)
- DeferredResult
- 개념
- 특정 이벤트에 반응해서 결과를 줄 때 유용하게 사용할 수 있는 기능
Servlet 3.2에서 등장- 처리 흐름
- 사용자의 request를 받아서 별도의 큐(
DeferredResult Queue)에 저장- request를 받은
servlet thread는 풀에 반납- 특정
Event가 생겼을 때,servlet thread pool에thread를 요청servlet thread를 할당받고 작업을 수행한 뒤, 사용자에게Response- 특징
- 특정
Event가 발생했을 때 작업을 처리한다 => 이름처럼지연된 결과- 별도의
worker thread를 생성하지 않는다- 작업 자체를
Event 기반으로Reactive하게 처리- 한계
- 완벽하게
Reactive하게 동작하는비동기 / 논블록킹방식을 구현하기에는 부족
=>DB 접근,API call등 모든 부분이논블록킹 방식으로 되어있어야 하기 때문
=>WebFlux의 필요성 !
- 특징
- Request를
Event-Driven방식으로 처리 (기본 WAS가Netty)
=>사용자의 요청/application 작업모두 Event로 관리
=>Event Queue에Event가 쌓인다
=>Event Loop를 통해 순차적으로 처리- 요청을 받는 Thread가
Blocking되지 않는다
=>Context Switching이 적다- 결과적으로,
완전한 논블록킹으로 구성된다면,
적은 Thread를 통해많은 처리를 할 수있는효율적인 모델을 구축할 수 있다
- 주의
- 오히려
Blocking I/O가 발생하면SpringMVC에 비해 성능이 떨어질 수 있음
=> 상대적으로적은 Thread Pool이기 때문논블록킹 Data Access를 사용해야 한다
=> JDBC 기반의 기술들(JPA등)은 결국 모두Blocking하게 동작WebClient를 통한논블록킹 api call이 필요하다
=> 기존의RestTemplate은 기본적으로Blocking하게 동작
- https://www.youtube.com/watch?v=aSTuQiPB4Ns
- https://tv.kakao.com/channel/3150758/cliplink/391418995
- https://madplay.github.io/post/spring-webflux-references-overview
- https://www.baeldung.com/spring-deferred-result
- https://dzone.com/articles/spring-webflux-eventloop-vs-thread-per-request-mod
- https://www.youtube.com/watch?v=I0zMm6wIbRI&t=721s