- 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를 채택
- 기본으로
Netty
WAS 사용 =>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