본문 바로가기

개발/Spring

#4) Spring WebFlux(기술 스택 차이, 요청 처리 흐름, 핵심 컴포넌트, 프로세스 구조)

 

1. Spring MVC와 Spring WebFlux의 기술 스택 비교

1-1 서버

Spring MVC : Servlet 기반의 프레임워크로 서블릿 컨테이너에서 Blocking I/O로 동작한다.

Spring WebFlux : Non-Blocking I/O 방식으로 동작하는 Netty 등 서버 엔진에서 동작한다.

 

1-2 서버 API

Spring MVC : 서블릿 API를 사용한다. 

Spring WebFlux : 기본 서버 엔진은 Netty지만 Jetty나 Undertow같은 서버 엔진에서 지원하는 Reactive Streams Adaptor를 통해 지원한다.

 

1-2 보안

Spring MVC : 표준 서블릿 필터를 사용하는 Spring Security를 사용한다.

Spring WebFlux : WebFilter를 이용해 Spring Security를 사용한다.

 

1-3 데이터 엑세스

Spring MVC : Blocking I/O 방식인 Spring Data JDBC, Spring Data JPA같은 기술을 사용한다.

Spring WebFlux : Non-Blocking I/O를 지운하는 Spring Data R2DBC, NoSQL 모듈을 사용한다.

 

2. Spring WebFlux의 클라이언트 요청 처리 흐름

 

1. 클라이언트 요청이 들어오면 Netty 등의 서버 엔진을 거쳐 HttpHandler가 요청을 전달받는다. HttpHandler는 서버 엔진에서 지원하는 서버 API를 사용할 수 있도록 추상화해 주는 역할을 한다. ServerHttpRequest와 ServerHttpResponse를 포함하는 ServerWebExchange를 생성 후 WebFilter 체인으로 전달한다.

 

2. ServerWebExchange는 WebFilter를 거친 후 WebHandler 인터페이스의 구현체인 DispatcherHandler에게 전달된다.

 

3. DispatcherHandler는 Spring MVC의 DispatcherServlet과 유사한 역할을 하는데 HandlerMapping List를 원본 Flux의 소스로 전달 받는다.

 

4. ServerWebExchange를 처리할 핸들러를 조회하고 핸들러의 호출을 HandlerAdapter에게 위임한다.

 

5. HandlerAdapter는 ServerWebExchange를 처리할 핸들러를 호출한다.

 

6. Controller 혹은 HandlerFunction 형태의 핸들러에서 요청을 처리 후 응답 데이터를 리턴한다.

 

7. 핸들러가 리턴한 응답 데이터를 처리할 HandlerResultHandler를 조회한다.

 

8. HandlerResultHandler가 응답 데이터를 처리한 후 response로 리턴한다.

 

3. Spring WebFlux의  핵심 컴포넌트

3-1 HttpHandler

다른 유형의 HTTP 서버 API로 request와 response를 처리하기 위해 추상화된 하나의 메서드만 가진다.

public interface HttpHandler {

	/**
	 * Handle the given request and write to the response.
	 * @param request current request
	 * @param response current response
	 * @return indicates completion of request handling
	 */
	Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response);

}

 

HttpHandler의 구현체인 HttpWebHandlerAdapter의 handle 메서드를 보면 ServerWebExchange를 생성한 후 WebHandler를 호출하는걸 볼 수 있다.

 

3-2 WebFilter

WebFilter는 핸들러가 요청을 처리하기 전에 전처리 작업을 할 수 있도록 해준다. 주로 보안, 세션 처리 등 어플리케이션에서 공통으로 필요한 전처리에 사용된다.

public interface WebFilter {

	/**
	 * Process the Web request and (optionally) delegate to the next
	 * {@code WebFilter} through the given {@link WebFilterChain}.
	 * @param exchange the current server exchange
	 * @param chain provides a way to delegate to the next filter
	 * @return {@code Mono<Void>} to indicate when request processing is complete
	 */
	Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain);

}

 

filter 메서드 하나로 정의되있으며 ServerWebExchange와 WebFilterChain을 파라미터로 받는다. WebFilterChain을 통해 필터 체인을 형성하기 때문에 원하는 만큼 Webfilter를 추가할 수 있다.

 

3-3 HandlerFilterFunction

함수형 기반의 요청 핸들러에 적용할 수 있는 Filter다. WebFilter는 Spring Bean으로 등록되지만 HandlerFilterFunction은 Spring Bean으로 등록되지 않는다. 

 

3-4 DispatcherHandler

WebHandler 인터페이스 구현체로 중앙에서 먼저 요청을 전달받고 다른 컴포넌트에 요청 처리를 위임하는 역할을 한다 (Spring MVC에 Front Controller 패턴이 적용된 DispatccherServlet과 비슷하다)

자체가 Spring Bean으로 등록되며 ApplicationContext에서 HandlerMapping, HandlerAdapter, Handler ResultHandler 등의 요청 처리를 위한 컴포넌트를 검색한다. 

 

3-5 HandlerMapping

request와 handler object에 대한 매핑을 정의하는 인터페이스다. 구현 클래스는 RequestMappingHandlerMapping, RouterFunctionMapping 등이 있다. 

 

3-6 HandlerAdapter

HandlerMapping을 통해 얻은 핸들러를 직접 호출하는 역할을 한다. 응답 결과로는 Mono<HandlerResult>를 리턴받는다.

구현 클래스는 RequestMappingHandlerAdapter, HandlerFunctionAdapter, SimpleHandlerAdapter, WebSocketHandlerAdapter가 있다.

 

 

 

 

4. 프로세스 구조

Spring MVC와 Spring WebFlux는 동시성 모델과 스레드에 대한 기본 전략에서 많은 차이점이 있다.

 

Spring MVC : Block I/O 방식 / 스레드가 차단될 수 있기 때문에 대용량의 스레드 풀을 사용해서 하나의 요청 당 하나의 스레드가 처리

Spring WebFlux : Non-Blocking I/O 방식 / 스레드가 차단되지 않기 때문에 적은 수의 고정된 스레드 풀을 사용해서 요청을 처리한다.

 

Spring WebFlux가 적은 수의 스레드로 스레드 차단 없이 많은 요청을 처리할 수 있는 이유는 이벤트 루프 방식을 사용하기 때문이다.

 

이벤트 루프 Non-Blocking 프로세스 

1. 클라이언트의 요청을 요청 핸들러가 전달받는다.

2. 전달받은 요청을 이벤트 루프에 Push한다.

3. 이벤트 루프는 비용이 드는 작업(네트워크, DB연결)에 대한 콜백을 등록한다.

4. 작업이 완료되면 완료 이벤트를 이벤트 루프에 Push한다.

5. 등록된 콜백을 호출해 처리 결과를 전달한다.

 

이벤트 루프는 단일 스레드에서 계속 실행되며 클라이언트 요청, DB I/O, 네트워크 I/O 등 모든 작업이 이벤트로 처리되므로

이벤트 발생 시 해당 이벤트에 대한 콜백을 등록함과 동시에 다음 이벤트 처리로 넘어간다. 그러므로 적은 수의 스레드로 많은 수의 요청을 Non-Blocking 프로세스로 처리할 수 있다.

 

반응형