[Spring] Webflux

BBinss·2021년 1월 28일
0
post-thumbnail

Spring WebFlux

Spring의 비동기 Event Loop기반의 표준 기술인 WebFlux를 통해서 한정적인 Tomcat Thread를 더욱 효율적이고 고사양적으로 사용할 수 있을지 확인.

전제

Spring에서 제공하는 publishOn() 메소드 혹은 DB non-blocking 접근을 지원하는 라이브러리들이 개발되고 있다.
다만 어플리케이션 로직에서 blocking 으로 처리되고 있는 부분이 있다면, 오히려 성능이 떨어지거나 추가적인 이슈가 발생해 Spring MVC 모델보다 비효율적일 수 있다.

테스트

  1. Spring tomcat thead의 최대 개수를 2개로 설정.
  2. 3개의 request 호출 : blocking 형태로 10초 delay API.
  3. 3개의 request 호출 : WebFlux를 통해 non-blocking 형태로 10초 delay API.

build.gradle

dependencies {
    // Spring Boot 2.3.8.RELEASE
    ['spring-boot-starter-web', 'spring-boot-starter-webflux'].each {
        implementation "org.springframework.boot:$it"
    }
}

application.yml

# 기본 200
server:
  tomcat:
    threads:
      max: 2

RestController

@RestController
@Slf4j
public class IndexApiController {
    private final WebClient webClient = WebClient.builder().build();

    @GetMapping("/{delay}")
    public Mono<String> index(
            @PathVariable int delay
    ) {
        Mono<String> result = webClient.get()
                .uri("http://postman-echo.com/delay/" + delay)
                .retrieve()
                .bodyToMono(String.class);

        log.info("non blocking - Delay");

        return result;
    }

    @GetMapping("/blocking/{delay}")
    public String blocking(
            @PathVariable int delay
    ) {
        log.info("blocking - Delay");

        return webClient.get()
                .uri("http://postman-echo.com/delay/" + delay)
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }
}

호출1 - 3개의 request : blocking 형태로 10초 delay API

[io-10999-exec-1] c.controller.IndexApiController      : blocking - Delay
[io-10999-exec-2] c.controller.IndexApiController      : blocking - Delay
.
.
.
[io-10999-exec-1] c.controller.IndexApiController      : blocking - Delay

11689ms, 10453ms, 18964ms 소요.
최대 thread 2개이므로, 2개의 request를 처리하는 동안 3번째 요청은 대기하게 된다. 2개중 1개의 요청을 처리한 이후 3번째 요청을 처리해서 결국 약 18.9초의 응답 시간으로 반환.

호출2 - 3개의 request 호출 : WebFlux를 통해 non-blocking 형태로 10초 delay API

[io-10999-exec-2] c.controller.IndexApiController      : non blocking - Delay
[io-10999-exec-2] c.controller.IndexApiController      : non blocking - Delay
[io-10999-exec-2] c.controller.IndexApiController      : non blocking - Delay

10484ms, 10437ms, 10427ms 소요.
request를 받은 thread가 API를 호출하고 blocking 되지 않고 바로 반환되기 때문에 3번째 요청도 대기 없이 처리. 1개의 thread만으로도 충분히 요청과 응답을 처리.

결론

non-blocking Event Loop 방식을 통해 효율적인 thread 사용이 가능.
적은 thread 개수로 처리가 가능하여 context switching 비용 감소.
대량의 request를 처리해야 하며, non-blocking 적인 액션들로 구성이 가능한 프로젝트에서 큰 성능을 발휘할 것으로 생각된다.

참고

profile
궁빈

0개의 댓글