Spring MVC는 기본적으로 블럭킹이고 동기방식을 사용합니다. 비동기 처리 기능이 스프링 프레임워크 3에서 추가되어 지원된다고 하지만, 서블릿은 응답을 기다리는 동안 pool의 스레드들은 여전히 지연시킬 수 있기 때문에 전체 stack이 reactive 해야 하는 요구를 충족시킬 수 없습니다.
이러한 요구사항에 맞추어 스프링 프레임워크5에 도입된 대안적인 모듈이 바로 WebFlux로써 웹 요청을 reactive 하게 다루는 데에 초점이 맞추어져 있습니다.
기존의 서블릿 기반의 Spring Boot는 Tomcat을 기반으로 동작합니다. 반면 Spring Boot WebFlux는 여러 가지를 고를 수 있는데 Default롤 Netty를 사용합니다. Netty를 사용하는 이유는 tomcat은 요청 당 하나의 스레드가 동작하는 반면, netty는 1개의 이벤트를 받는 스레드와 다수의 worker스레드로 동작하게 됩니다.
그렇다면 netty의 동작방식에 대해 좀 더 자세히 알아보도록 하겠습니다.
netty는 channel에서 발생하는 이벤트를 EventLoop가 처리하는 구조로 동작합니다. NodeJS를 사용해보신 분들이라면 이벤트 루프라는 키워드가 낯설지 않을 것 같은데, 구체적으로 어떤 기술인지 확인하고 넘어가도록 하겠습니다.
이벤트 루프란 이벤트를 실행하기 위한 무한루프 스레드를 뜻합니다.
위의 이미지와 같이 객체에서 발생한 이벤트는 이벤트 큐에 push 되고 이벤트 루프는 이벤트 큐에 입력된 이벤트가 있을 때 해당 이벤트를 꺼내서 실행합니다.
이벤트 루프는 지원하는 스레드의 종류에 따라서 단일 스레드와 다중 이벤트 루프로 나누어지게 됩니다. 또한 이벤트 루프가 처리한 이벤트의 결과를 돌려주는 방식에 따라 콜백 패턴과 퓨처 패턴으로 나누어지게 되고, netty는 이 두 가지 패턴을 모두 지원합니다.
싱글 스레드
싱글 스레드 이벤트 루프는 말 그대로 이벤트를 처리하는 스레드가 하나인 상태를 이야기 합니다. 단일 스레드로 동작하기 때문에 예측 가능한 동작을 보장하고, 이벤트 루프의 구현이 단순하다는 장점이 있습니다. 하지만 하나의 처리시간이 긴 작업이 들어오면 전체 작업 지연시간이 늘어난다는 단점이 있습니다. 또한 단일 스레드이기 때문에 멀티 코어 cpu환경에서 cpu자원을 효율적으로 사용할 수 없습니다.
멀티 스레드
멀티 스레드 이벤트 루프는 이벤트를 처리하는 스레드가 여러 개인 모델입니다. 싱글 스레드 이벤트 루프에 비해 프레임워크 구현이 복잡하지만, 스레드들이 이벤트 메서드를 병렬로 수행하기 때문에 멀티 코어 cpu의 자원을 효율적으로 사용할 수 있습니다. 하지만 여러 이벤트 스레드가 하나의 이벤트 큐에 접근하기 때문에 동시성 문제가 발생할 수 있습니다. 또한 이벤트들이 병렬로 처리되기 때문에 이벤트의 발생순서와 실행 순서가 일치하지 않습니다.
Netty에서는 멀티 스레드 이벤트 루프의 단점인 발생 순서와 실행 순서가 일치하지 않는 다는 문제를 아래와 같은 방법으로 해결합니다.
- Netty의 이벤트는 Channel에서 발생합니다.
- 각각의 이벤트 루프 객체는 개인의 이벤트 큐를 가지고 있습니다.
- Netty Channel은 하나의 이벤트 루프에 등록됩니다.
- 하나의 이벤트 루프 스레드에는 여러 채널이 등록될 수 있습니다.
멀티 스레드 이벤트 모델에서 이벤트의 실행 순서가 일치하지 않는 이유는 루프들이 이벤트 큐를 공유하기 때문에 발생하게 됩니다. 따라서 Netty는 이벤트 큐를 이벤트 루프 스레드의 내부에 둠으로써 실행 순서의 불일치 원인을 제거하게 됩니다.
즉 이벤트 루프 스레드마다 개인의 이벤트 큐를 가짐으로써, 해당 이벤트를 처리하는 스레드가 지정되어 있기 때문에 공유된 하나의 이벤트 큐에 스레드들이 접근하지 않게 됩니다.
'Server > Spring (Boot & Framework)' 카테고리의 다른 글
[Spring] 비동기 처리시 blocking 되는 servlet thread 관리 (1) | 2021.09.25 |
---|---|
[Spring] Spring Batch: 대용량 데이터를 처리하는 프레임워크 (0) | 2020.06.26 |
[Spring] Bean Scope와 Bean Life Cycle (0) | 2020.05.26 |
[Spring] iBatis/MyBatis: 쿼리 return결과 (0) | 2020.04.08 |
[Spring] Spring MVC: Controller return 타입 (0) | 2020.04.06 |