기술 면접(WebFlux)

유요한·2023년 11월 22일
0

기술면접

목록 보기
15/27
post-thumbnail

리액티브 프로그래밍이란?

리액티브 시스템을 구축하는데 필요한 프로그래밍 모델입니다. 리액티브 시스템에서의 비동기 메시지 통신은 Non-Blocking I/O 방식의 통신입니다.

Blocking I/O 방식의 통신에서는 해당 스레드가 작업을 처리할 때 까지 남아 있는 작업들은 해당 작업이 끝날 때까지 차단되어 대기합니다. 그렇기 때문에 뒤에 남아 있는 작업들을 대기 없이 처리하려면 별도의 추가 스레드를 할당해야 해서 그만큼의 비용이 더 들게 됩니다.

Non-Blocking I/O 방식의 통신에서는 말 그대로 스레드가 차단되지 않습니다.

리액티브 프로그래밍은 데이터 흐름(data flows)과 변화 전파에 중점을 둔 프로그래밍 패러다임(programming paradigm)이다. 이것은 프로그래밍 언어로 정적 또는 동적인 데이터 흐름을 쉽게 표현할 수 있어야하며, 데이터 흐름을 통해 하부 실행 모델이 자동으로 변화를 전파할 수 있는 것을 의미한다.

  • 변화의 전파와 데이터 흐름 : 데이터가 변경 될 때마다 이벤트를 발생시켜서 데이터를 계속적으로 전달

  • 선언적 프로그래밍 : 실행할 동작을 구체적으로 명시하는 명령형 프로그래밍과 달리 선언형 프로그래밍은 단순히 목표를 선언

특징

  • declarative programming
    선언형 프로그래밍이라는 의미입니다. 명령형 프로그래밍방식과 달리 실행할 동작을 구체적으로 명시하지 않고 이러이러한 동작을 하겠다는 목표만 선언합니다.

  • data streams와 the propaging of change
    data streams라는 것은 데이터 흐름, 즉 데이터가 지속적으로 발생한다는 의미이고 the propaging of change는 지속적으로 데이터가 발생할 때마다 이것을 변화하는 이벤트로 보고 이 이벤트를 발생시키면서 데이터를 계속적으로 전달하는 것을 의미합니다.

리액티브 프로그래밍을 사용하는 이유

  • 비동기적인 이벤트 처리
    리액티브 프로그래밍에서는 이벤트를 비동기적으로 처리하기 때문에, 이벤트가 발생하는 즉시 처리할 수 있습니다. 이는 일반적으로 스레드에 의존하는 전통적인 동기적인 프로그래밍 방식보다 훨씬 효율적이며, 대규모 시스템에서 높은 성능을 보장합니다.

  • 데이터 스트림 처리
    리액티브 프로그래밍에서는 데이터 스트림을 다룰 수 있습니다. 이러한 데이터 스트림은 무한하거나 큰 양일 수 있으며, 이벤트가 발생할 때마다 해당 이벤트를 처리하는 콜백 함수를 등록합니다. 이러한 방식은 대규모 데이터 처리에 적합합니다.

  • 반응형 시스템 구현
    액티브 프로그래밍은 반응형 시스템을 구현하는 데 적합합니다. 이는 시스템이 외부 요청에 신속하게 반응하고, 빠른 응답 시간을 제공할 수 있도록 하는 기능입니다.


Spring WebFlux

Spring Webflux를 학습하기에 앞서 Spring MVC의 Thread Poll에 대해서 학습할 필요가 있다.

Spring MVC의 Thread Pool
Spring MVC 프레임워크는 Multi-ThreadBlocking방식을 사용한다.

Blocking 방식

요청한 작업이 끝날 때 까지 다른 작업을 하지 않고 끝날 때 까지 기다리는 것이다. 즉, 하나의 스레드가 요청을 처리하기 위해 처리함수를 실행하면 제어권도 함께 넘겨 해당 함수가 끝이날 때까지 다른 함수를 호출할 수 없는 것이다.

Spring MVC 프레임워크는 클라이언트가 접속을 하게 되면 서버에 쓰레드를 모아논 쓰레드 풀에서 하나씩 분배해주게 되고 접속이 끝이 나면 다음 클라이언트에게 해당 쓰레드를 주게된다. 만약 클라이언트가 많아져 쓰레드 풀의 남은 쓰레드가 없으면 Queue 공간에 클라이언트가 쌓이게 된다.

그래서 클라이언트의 접속수가 증가하면(동시성이 증가)
CPU,메모리가 충분하더라도 쓰레드가 부족하여 성능이 떨어질수 있게 된다. 또한 쓰레드를 늘리게 되면 메모리,CPU성능이 떨어지기 때문에 무조권적으로 쓰레드를 늘린다고 해결될수 없다.

대부분 Spring MVC에서는 동시성을 스레드를 늘려 처리한다고 한다.

Spring WebFlux란 Client, Server에서 reactive 스타일의 어플리케이션의 개발을 도와주는 스프링 모듈이다. 스프링의 리엑티브 스택의 웹파트를 담당하고 있는 프레임워크이다.

Spring Webflux는 Single-ThreadNon-Blocking방식을 사용한다.

Non-Blocking방식

요청한 작업이 수행되는 공간 다른 작업을 할 수 있는 방식이다. 즉, 호출자가 함수를 호출할 때 제어권을 호출자가 가지고 있어서 다른 작업을 할 수 있다.

Spring Webflux는 적은 수의 스레드를 사용하여 여러 클라이언트의 요청을 처리할수 있다. 그럼 Spring Webflux가 Spring MVC보다 좋을수 있다고 생각할수 있다. 그건 아니다. 자원측면에서는 Spring Webflux는 적은 스레드로 자원(메모리,CPU)를 효율적으로 사용할수 있다. 하지만 속도측면에서는 리엑티브, 논블로킹 방식인 Spring Webflux은 어플리케이션의 속도를 향샹시키지는 못한다. 즉, 적은 리소스(스레드,메모리,CPU)로 많은 트래픽을 처리할수 있다.

WebFlux vs MVC

MVC의 한계

대용량 요청 트래픽을 Spring MVC 방식이 처리하기에는 한계가 있다.

트래픽이 많아지면 많아질 수록 스레드도 많이 사용하는데 스레드풀에 스레드 200개가 default로 존재하고 만약 그것에 동시접속한다면 스레드 스위칭 비용도 그만큼 많이 발생한다.

WebFlux를 이용한 극복

대용량 트래픽을 감당하기 위해선 비동기/논블로킹 방식의 I/O를 사용해야 했으며, 이 방식이 적용되어 대용량도 안정적으로 처리할 수 있는 WebFlux가 탄생했다.

차이

client가 백엔드 서버로 요청을 보내면,백엔드 서버는 외부 서버로 요청을 보내게 되는데 이때 외부 서버의 동작이 5초 걸린다고 가정하자.

  • MVC의 경우
    MVC는 서블릿 기반 동기식 처리를 한다. 외부 서버로 요청을 보낼 때 동기 처리를 하는 RestTemplate을 사용해서 처리를 한다고 했을 때 5번(요청) * 5초(외부 서버의 응답 처리시간) == 총 25초가 걸릴것이다. 외부 서버와 통신할 때 요청처리스레드는 블로킹(Blocking) 된다.

  • WebFlux의 경우
    웹플럭스는 비동기 넌블로킹 방식의 리액티브 프로그래밍을 지원한다. 이때 외부 서버로 요청을 보내면서 WebClient를 사용하면 5번의 요청에서 블로킹이 발생하지 않는다. 외부 서버에서 5초 걸리는것을 우리서버에서 기다리지 않는다는 것이다. MVC와 비교해서 대용량 처리가 필요한 상황에서 아주 빠른 처리를 할 수 있다.

Spring Webflux의 내부 동작 원리

Client의 요청이 발생하면 서버엔진인 Netty를 거치게 된다.

  1. HttpHandler가 서버 API를 추상화한다.
  • 네티 뿐만 아니라 다양한 서버엔진이 지원된다.
  • ServerWebExchange를 생성한다. 이 친구한테 ServletHttpRequest, ServletHttpResponse가 포함되어있다.
  1. WebFilter
  • 필터체인으로 구성된 웹 필터이다.
  • ServerWebExchange의 전처리 과정을 실천한다.
  • 이후 Web handler의 구현체인 Dispatcher Handler에게 전달된다.
  1. DispatchHandler
  • SpringMVC의 Dispatcher Servlet과 유사한역할
  • Handler Mapping에게서 핸들러매핑 리스트를 받아서, 원본 Flux의 소스로 전달받는다.
  1. getHandler
    ServerWebExchanger를 처리할 핸들러를 조회한다.

  2. 핸들러 어댑터에게, ServerWebExchanger를 처리하도록 위임한다.

  3. HandlerAdapter

  • 핸들러어댑터는 핸들러를 호출한다.
  • 이때 호출되는 핸들러의 형태는 Controller, Handler Function 형태이며, Mono<HandlerResult>를 반환한다.
  1. 반환받은 응답데이터를 처리할 HandlerResultHandler를 조회한다.
  2. HandlerResultHandler
    응답 데이터의 적절한 처리 후 return한다.

Netty의역할

  • 네티는 서버엔진으로 네트워크 I/O 이벤트에 대한 콜백 함수를 등록하고 관리한다.
  • 콜백 함수는 특정 이벤트가 발생할 때 자동으로 호출된다.
  • 요청처리 방식을 이벤트 루프 방식으로 사용하였고, 이벤트 루프는 단일스레드를 사용한다.

HttpHandler에 가기전 서버엔진에서는 어떤 일이 일어날까?
1. 먼저 Client들의 요청은 요청핸들러를 거친다.
2. 요청에 대한 event를 생성하고, 이벤트 루프에 넣는다(push)
3. 이벤트 루프는 (비용이 드는) 작업에 대한 콜백을 등록한다.
4. 작업이 완료된 것은 완료 이벤트를 이벤트 루프에 push한다. 이를 통해 원래 콜백이 실행된다.
(콜백이 작업의 결과를 처리한다)
5. 등록된 콜백이 호출해 처리 결과를 전달한다. 결과가 클라이언트에게 반환된다.

profile
발전하기 위한 공부

0개의 댓글