Spring Webflux와 Spring MVC 모델을 통한 비교

Single Ko·2024년 8월 21일
0

reactive-programing

목록 보기
8/8

WebFlux & MVC

Spring 프레임워크에는 크게 두 가지 웹 프로그래밍 모델이 있습니다. Spring MVC와 Spring WebFlux입니다. 이 두 모델 간의 가장 큰 차이점은 비동기 처리 방식입니다.

전통적인 Spring MVC 모델은 Servlet 기반의 동기/블로킹 방식으로 동작합니다. 즉, 클라이언트의 요청이 들어오면 스레드가 blocking되어 해당 요청을 처리할 때까지 기다려야 합니다. 이로 인해 동시 사용자 증가 시 리소스 사용량이 늘어나는 문제가 있습니다.

반면, Spring WebFlux는 Reactor 기반의 비동기/논 블로킹 방식으로 동작합니다. 요청을 받으면 즉시 반환하고, 백그라운드에서 비동기적으로 데이터를 처리합니다. 이를 통해 적은 수의 스레드로도 높은 처리량을 달성할 수 있습니다.

외부 API를 호출하는 간단한 앱을 만든다고 가정해 봅시다. 전통적인 Spring MVC 방식과 Spring WebFlux 방식으로 구현한 코드는 다음과 같습니다


// Spring MVC (RestTemplate)

@GetMapping("/products")
public List<Product> getProducts() {
    List<Product> list = restClient.get()
            .uri("/demo01/products")
            .retrieve()
            .body(new ParameterizedTypeReference<List<Product>>() {});
    log.info("received response: {}", list);
    return list;
}

// Spring WebFlux (WebClient)  
@GetMapping("/products")
public Flux<Product> getProducts() {
    return webClient.get()
            .uri("/demo01/products")
            .retrieve()
            .bodyToFlux(Product.class)
            .doOnNext(product -> log.info("received: {}", product));
}

/demo01/products는 1초에 한번씩,10개의 Product의 정보를 생성하는 기능을 가지고 있습니다.

처리방식

MVC
동기적인 방식의 mvc 모델은 모든 데이터를 한 번에 받아옵니다. 1초마다 생성되는 Product 정보를 전부 기다렸다가 List로 한꺼번에 반환합니다. 따라서 이 메서드는 모든 데이터가 준비될 때까지 블로킹됩니다.

WebFlux
이에반헤 WebFlux를 이용한 모델은 데이터를 스트리밍 방식으로 받아옵니다. 1초마다 생성되는 Product 정보를 매초마다 계속 처리할 수 있습니다. Flux를 통해 데이터가 준비되는 대로 비동기적으로 전달됩니다.

리소스 사용

MVC: 요청이 완료될 때까지 스레드가 블로킹됩니다.
WebFlux: 논블로킹 방식으로 작동하여 적은 수의 스레드로 많은 요청을 처리할 수 있습니다.

오류 처리

Spring MVC

@GetMapping("/products")
public ResponseEntity<List<Product>> getProducts() {
    try {
        List<Product> list = restClient.get()
                .uri("/demo01/products")
                .retrieve()
                .body(new ParameterizedTypeReference<List<Product>>() {});
        return ResponseEntity.ok(list);
    } catch (RestClientException e) {
        log.error("Error fetching products", e);
        return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).build();
    }
}

이 방식에서는 try-catch 블록을 사용하여 예외를 잡아내고 적절한 오류 응답을 반환해야 합니다. 또한 서버가 중간에 다운되면 데이터는 소실됩니다.

Spring WebFlux

@GetMapping("/products")
public Flux<Product> getProducts() {
    return webClient.get()
            .uri("/demo01/products")
            .retrieve()
            .bodyToFlux(Product.class)
            .doOnNext(product -> log.info("received: {}", product))
            .onErrorResume(e -> {
                log.error("Error fetching products", e);
                return Flux.empty();
            });
}

WebFlux에서는 onErrorResume, onErrorComplete 등을 사용하여 오류를 쉽게 처리할 수 있습니다. 오류가 발생하면 빈 Flux를 반환하거나, 대체 데이터를 제공하는 등의 방식으로 유연하게 오류를 처리할 수 있습니다.

WebFlux의 방식이 더 유연하고 선언적인 오류 처리를 가능하게 합니다. 또한, 스트리밍 방식으로 데이터를 처리하기 때문에 서버가 중간에 다운되더라도 이미 받은 데이터는 처리할 수 있습니다.

profile
공부 정리 블로그

0개의 댓글