티스토리 뷰

위 그림은 DZone 게시글 중 하나인 Spring WebFlux를 이용한 Boot2와 Spring MVC를 이용한 Boot1을 비교한 그래프이다.

 

해당 그래프에서는 두 가지 특징을 볼 수 있다.


첫 번째로는 유저가 적을 때에는 성능에 별반 차이가 없다. 두 번째로는 유저가 늘어나면 늘어날수록 극명한 성능 차이를 보여주고 있다. 어떻게 이런 차이가 일어날 수 있을까?

 

본글은 아래의 구성을 가지고 있다.

 

  1. I/O
  2. Event-Driven
  3. Spring Framework

먼저, 1과 2를 통해서 원리를 알아본 다음 3에서 이를 접목시켜서 위의 그래프가 나올수 있는 이유를 설명할 것이다.

I / O

Why was Spring WebFlux created?

Part of the answer is the need for a non-blocking web stack to handle concurrency with a small number of threads and scale with fewer hardware resources. – Spring Document

핵심만 말하자면 non-blocking을 통해서 적은 수의 리소스로 동시성을 다룬다는 것이다. I/O의 원리부터 시작해서 non-blocking에 대해서도 이해해보도록 하자.

io

사용자가 I/O 요청을 할 때 CPU가 I/O Controller에 요청을 하고 I/O Controller가 파일을 다 가져오면 그것을 Memory에 적재시키고 CPU에게 완료되었다고 알려준다. 즉 큰 그림은 CPU -> I/O Controller -> CPU의 형태이다.

 

핵심은 CPU가 I/O를 직접 가져오는 것이 아니라, 작은 CPU라고 불리는 I/O Controller가 수행한다는 이야기이다. 좀 더 나아가면 작업을 단순히 위임시키고 작업이 완료되는 동안에는 다른 일을 수행할 수 있다는 말이다. 이러한 예처럼 I/O를 처리하는데 몇 가지 방법이 있다.

Blocking I/O

blocking io

가장 기본적인 I/O 모델이며 여러분들이 Spring MVC와 RDBMS를 사용하고 있으면 대부분 이 모델을 사용하고 있을 것으로 예상된다.

 

Application에서 I/O 요청을 한 후 완료되기 전까지는 Application이 Block이 되어 다른 작업을 수행할 수 없다. 이는 해당 자원이 효율적으로 사용되지 못하고 있음을 의미한다.

 

그러나 생각을 해보면 여러분들의 Application들은 Blocking 방식임에도 불구하고 마치 Block이 안된듯이 동작하는 것처럼 보인다. 이것은 여러분들이 Single Thread를 기반으로 하는 것이 아닌 Multi Thread를 기반으로 동작하기 때문이다. Block 되는 순간 다른 Thread가 동작함으로써 Block의 문제를 해소하였다. 그러나 Thread 간의 전환(Context Switching)에 드는 비용이 존재하므로 여러 개의 I/O를 처리하기 위해 여러 개의 Thread를 사용하는 것은 비효율적으로 보인다.

Synchronous Non-Blocking I/O

non blocking io


Application에서 I/O를 요청 후 바로 return되어 다른 작업을 수행하다가 특정 시간에 데이터가 준비가 다되었는지 상태를 확인한다. 데이터의 준비가 끝날 때까지 틈틈이 확인을 하다가 완료가 되었으면 종료된다.

 

여기서 주기적으로 체크하는 방식을 폴링(Polling) 이라고 한다. 그러나 이러한 방식은 작업이 완료되기 전까지 주기적으로 호출하기 때문에 불필요하게 자원을 사용하게 된다.

Asynchronous Non-blocking I/O

async non blocking io


I/O 요청을 한 후 Non-Blocking I/O와 마찬가지고 즉시 리턴된다. 허나, 데이터 준비가 완료되면 이벤트가 발생하여 알려주거나, 미리 등록해놓은 callback을 통해서 이후 작업이 진행된다.

 

이전 두 I/O의 문제였던 Blocking이나 Polling이 없기 때문에 자원을 보다 더 효율적으로 사용할 수 있다.
(이후로는 편의상 Non-Blocking I/O라고 하겠다.)


Java 코드를 통해서 이를 이해해보자.

Blocking I/O

@Test
public void blocking() {
    final RestTemplate restTemplate = new RestTemplate();

    final StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    for (int i = 0; i < 3; i++) {
        final ResponseEntity<String> response =
                restTemplate.exchange(THREE_SECOND_URL, HttpMethod.GET, HttpEntity.EMPTY, String.class);
        assertThat(response.getBody()).contains("success");
    }

    stopWatch.stop();

    System.out.println(stopWatch.getTotalTimeSeconds());
}

Spring의 HTTP 요청 라이브러리인 RestTemplate을 사용하여 3초가 걸리는 API를 3번 호출하였다. 결과는 여러분도 알다시피 9.xx초가 나온다. 이유는 I/O가 요청 중일 때에는 아무 작업도 할 수 없기 때문이다.

Non Blocking I/O

@Test
public void nonBlocking3() throws InterruptedException {
    final StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    for (int i = 0; i < LOOP_COUNT; i++) {
        this.webClient
                .get()
                .uri(THREE_SECOND_URL)
                .retrieve()
                .bodyToMono(String.class)
                .subscribe(it -> {
                    count.countDown();
                    System.out.println(it);
                });
    }

    count.await(10, TimeUnit.SECONDS);
    stopWatch.stop();
    System.out.println(stopWatch.getTotalTimeSeconds());
}

WebFlux에서 제공하는 WebClient를 사용해서 위와 동일하게 3초가 걸리는 API를 호출하였다. for문 안의 변수인 LOOP_COUNT는 100으로 코드상에서 설정되어있다. 3초 걸리는 API를 100번 호출한다 하더라도 3.xx초 밖에 걸리지 않는다. 더 나아가서 LOOP_COUNT를 1000으로 변경하더라도 필자의 컴퓨터에서는 4.xx초 밖에 걸리지 않는다. Blocking I/O와 비교해봤을 때 정말 효율적이라고 볼 수 있다.

 

만약, Blocking을 위처럼 많은 요청을 동시에 처리하려면 그 만큼의 Thread이 생성되어야 한다. 그러나 이렇게 처리한다 해도 Context Swiching에 의한 오버헤드가 존재할 것이다.

Event-Driven

시장 조사 기관 가트너는 비즈니스 업계가 주목해야 할 2018 10대 전략기술 트렌드를 발표했고, Event-Driven가 포함되어 있다. 또한 Event-Driven을 토대로 많은 프레임워크와 라이브러리가 발전하고 있다. Spring WebFlux, Node.js, Vert.x 등이 그에 따른 예이다. 우리가 자주 접하는 기술들에 어떻게 스며들어 접목이 되었는지에 대해서 살펴보자.

 

Event-Driven Programming은 프로그램 실행 흐름이 이벤트(ex : 마우스 클릭, 키 누르기 또는 다른 프로그램의 메시지와 같은 사용자 작업)에 의해 결정되는 프로그래밍 패러다임이다. Event가 발생할 때 이를 감지하고 적합한 이벤트 핸들러를 사용하여 이벤트를 처리하도록 설계됐다. 순차적으로 진행되는 과거의 프로그래밍 방식과는 달리 유저에 의해 종잡을 수 없이 진행되는 GUI(Graphical User Interface)가 발전됨에 따라 Event-Driven 방식은 더욱더 많이 쓰이게 되었다.

 

대표적으로 우리 자주 접할 수 있는 방식은 아래와 같은 Click Event이다.

click event

아래는 Java를 이용하여 Click Event를 구현한 예이다.

JButton button = new JButton();
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("clicked");
    }
});

물론 Lambda Expression 사용하면 아래처럼 간결하게 표현이 가능하다.

JButton button = new JButton();
button.addActionListener(e -> System.out.println("clicked"));

우리는 Java 이외의 타 언어에서도 자연스럽게 Listener에 등록하여 Event를 구현하고 있다. 그런데 Button은 어떻게 유저에 의해 Click이 되었는지 인지할 수 있을까? 단순히 Listener에 등록하기만 하면 자동적으로 인지할까?

 

그렇지 않다.

 

과거로 돌아가 C언어로 키보드 Event를 핸들링하는 코드를 작성해보자.

int main(void){
    char key;
    while(1){
        key = getch();      // (1) 

        switch (key) {      // (2)
            case 1 : 실행문; break;
            case 2 : 실행문; break;
            case 3 : 실행문; break;
            case 4 : 실행문; break;
            default : 실행문; break;
        }
    }
    return 0;
}

위 코드는 두 가지 경우로 되어있다.
(1) 무한루프를 돌면서 사용자에 의해 Key가 눌러지는 것을 감지한다.
(2) 감지된 값을 토대로 해야 할 일을 알맞은 곳에서 처리한다.

 

이를 일반화시켜 말하면 다음과 같다.

Event Loop가 돌면서 Event를 감지한 뒤 Event Handler 또는 Event Listener에게 보내서 작업을 처리한다.

 

Java Swing에서는 내부적으로 어떻게 Event를 처리할까?

위의 c언어로 작성한 코드와 거의 동일하지 않은가? 단지 Event Queue만 추가되었을 뿐이다. 그러나 코드는 한편 간결해졌다.

JButton button = new JButton();
button.addActionListener(e -> System.out.println("clicked"));

일일이 Event를 제어했던 과거와는 달리 요즘은 이를 단순히 Listener에 행위만 등록해주면 간편하게 Event를 제어할 수 있다. 이는 Event Handle만이 관심의 대상이고 이에 집중할 수 있게 한다. 달리 말하면 Evevt Loop를 돌면서 요청을 감지하고 적합한 Handler에 위임해주는 부수적인 부분은 언어 레벨에서 처리를 해준다는 말이다.

 

이를 일반화하면 아래와 같은 이미지를 그릴 수 있다.

Event-Driven


Event-Driven이라는 키워드가 언급되면 위의 이미지를 기억에서 꺼내면 된다.

 

그리고 이러한 Event 처리는 Server에도 적합하다. 왜냐하면 HTTP Request라는 Event가 발생하기 때문이다. 그래서 Node.js, Spring WebFlux, Vert.x 등은 Event-Driven 형태로 Architecture가 구현되어있다.

Spring Framework


위 그림처럼 Spring은 Reactive Stack과 Servlet Stack 두 가지 형태를 제공한다. 또한 Reactive Stack은 non-blocking I/O를 이용해서 많은 양의 동시성 연결을 다룰 수 있다고 한다. 과거로 돌아가서 Servlet Stack의 문제점을 파악하고 이를 어떻게 Reactive Stack으로 해결했는지 알아보자.

Spring MVC


위 그림처럼 유저들로부터 HTTP 요청이 들어올 때 요청들은 Queue를 통하게 된다. Thread pool이 수용할 수 있는 수(thread pool size)의 요청까지만 동시적으로 작업이 처리되고 만약 넘게 된다면 큐에서 대기하게 된다. 즉 하나의 요청은 하나의 Thread를 요구한다. (one request per thread model)

 

Thread pool은 다음과 같다. Thread를 생성하는 비용이 크기 때문에 미리 생성하여 재사용함으로써 효율적으로 사용한다. 그렇다고 과도하게 많은 Thread를 생성하는 것이 아니라 서버 성능에 맞게 Thread의 최대 수치를 제한시킨다. 참고로 tomcat default thread size는 200이다.

 

그런데 만약 대량의 트래픽이 들어와 thread pool size를 지속적으로 초과하게 된다면 어떻게 될까?

queue


설정해놓은 thread pool size를 넘게 되면 위 그림처럼 작업이 처리될 때까지 Queue에서 계속해서 기다려야 한다. 그래서 전체의 대기시간이 늘어난다. 이런 현상을 Thread pool hell이라고 한다.

 

아래 사진은 Linkedin의 Thread pool hell 현상에 대한 그래프이다. Thread pool이 감당할 수 있는 요청수를 넘는 순간부터는 평소보다 수배나 많은 지연시간을 보여준다.

thread pool hell


Thread pool이 감당할 수 있을 때까진 빠른 처리속도를 보이지만, 넘는 순간부터는 지연시간이 급격하게 늘어난다.

 

하나의 작업이 늦게 처리되는 부분에 대해서도 우린 고민해 볼 필요가 있다. 독자분들이 만든 코드가 보통 왜 느려지는가? 특수한 경우를 제외하면 DB, Network 등의 I/O가 일어나는 부분에서 아마 시간을 많이 소비했을 것이다.

 

설명했듯이 I/O 작업은 CPU가 관여하지 않는다. I/O Controller가 데이터를 읽어오고 이를 전달받을 뿐이다. 위에서 I/O를 처리하는 3가지 방식을 소개했는데 가장 효율이 좋은 방법은 마지막에 설명한 Asynchronous Non-blocking I/O이라고 하였다. Blocking 방식은 I/O Controller가 데이터를 읽는 동안 CPU가 아무 일도 할 수가 없고, Non-Blokcing방식은 polling 때문에 불필요하게 CPU를 소비한다고 했다.

 

Spring에서도 Non-blocking I/O를 이용해서 효율적으로 작업을 처리할 수 있는 방법을 제공한다. 그 수단이 WebFlux이다.

Spring WebFlux

webflux event driven


위는 전반적인 WebFlux의 구조이다. 사용자들에 의해 요청이 들어오면 Event Loop를 통해서 작업이 처리가 된다. one request per thread model과의 차이점은 다수의 요청을 적은 Thread로도 커버할 수 있다. worker thread default size는 서버의 core 개수로 설정이 되어있다. 즉 서버의 core가 4개라면 worker thread는 4개라는 말이며 이 적은 Thread를 통해서도 traffic을 감당할 수 있다. 위에서 하나의 Thread로 3초가 걸리는 API 1000개를 호출했음에도 4초밖에 안 걸렸다는 걸 상기시키면 이해에 도움이 될 것이다. 또한 비슷한 Architecture를 가진 Node.js가 이미 증명을 하고 있다.

 

이렇듯 Non Blocking 방식을 활용하면 좀 더 효율적으로 I/O를 제어할 수 있고 성능에도 좋은 영향을 미친다. 특히나 유행하는 MSA에서는 수많은 Microservice가 거미줄처럼 서로를 네트워크를 통해서 호출하고 있다. 즉 많은 수의 Network I/O가 발생할 텐데 이를 Non Blocking I/O를 통해 좀 더 성능을 끌어올릴 수 있다.

 

그러나 물론 제한된 점이 있다. WebFlux로 성능을 최대치로 끌어올리려면 모든 I/O 작업이 Non Blocking 기반으로 동작해야 된다. Blocking이 되는 곳이 있다면 안 하느니만 못한 상황이 되어버린다.
예를 들어 멀티코어로 가정을 해보자. 그럼 처리할 수 있는 Thread는 2개인데 Blocking이 걸리는 API를 열명 이서 동시에 호출한다면 결국엔 Spring MVC처럼 8명이 I/O 작업이 끝날 때까지 기다려야 하는 구조가 되어버리기 때문이다.

What if you do need to use a blocking library? Both Reactor and RxJava provide the publishOn operator to continue processing on a different thread. That means there is an easy escape hatch. Keep in mind, however, that blocking APIs are not a good fit for this concurrency model. - Spring Document

대안으로 publicOn()을 사용하라고 하지만 마지막 문장 Blocking은 이 모델에 적합하지 않다고 한다.

 

Java 진영에는 아쉽게도 DB connection을 non-blokcing으로 지원하는 라이브러리가 널리 보급되어 잘 사용되지는 않고 있다. 다만 R2DBC처럼 개발이 진행 중인 라이브러리, 최근에 release된 jasync sql 등이 있으며, MongoDB, Redis 등의 NoSQL은 지원중이다. (피드백 주신 정상혁님 감사합니다.)

또한 소수의 Thread에 의해서 수많은 요청을 처리하고, 순서대로 작업이 처리되는 것이 아니라 Event에 기반하여 실타래가 엉킨 것처럼 작업이 처리되기 때문에 트래킹 하기에 힘이 들다는 문제가 있다.

 

그렇다면 성능이 좋으니 무조건 WebFlux를 사용해야 할까?
지금까지 필자의 글에 혹했다면 위의 질문처럼 잘못된 생각을 할 수도 있다.

webflux-performance


위 그림은 Spring MVC나 Spring WebFlux 둘 다 성능이 동일한 구간이 있다. 서버의 성능이 좋으면 좋아질수록 해당 구간은 더 늘어날 것이다. 그렇기에 만약 여러분의 환경이 해당 구간이라면 굳이 사용할 필요가 없다. 또한 Spring Document에서는 동기 방식이 코드 작성, 이해, 디버깅하기 더 쉽다고 한다. 이 말은 즉 높은 생산성을 가진다는 말과 같은 것으로 보인다. 그렇기에 이해타산을 잘 따져서 선택해야 할 필요가 있다.

 

그리고 우리는 이제 왜 성능이 동일한 구간이 생기는 지를 알 수 있다. 저 구간은 바로 Thread Pool이 감당할 수 있을 정도의 요청이었기에 비동기적으로 잘 수행하다가 이후에는 Queue에 쌓여 점점 성능이 느려졌던 것이다.

 

'Spring WebFlux는 어떻게 적은 리소스로 많은 트래픽을 감당할까?'란 궁금증을 시작으로 여기까지 왔다. 이에 대한 답은 I/O를 Non Blockkng을 이용하여 잘 사용하는 것과 Request를 Event-Driven을 통해서 효율적으로 처리하기 때문에 가능하다.

 

 

 

 

 

참고 자료

댓글
  • 이전 댓글 더보기
  • 프로필사진 chldnjstkd2 정말 좋은글이네요 이해가 다른글보다 더 이해가 되요!
    기존 mvc 하나의 요청에 하나의 쓰레드를 쓰지만
    webflux 는 하나 이상의 요청을 하나의 쓰레드를 통해 동작한다는건가요?
    2019.08.03 13:25
  • 프로필사진 AlwaysPr webflux에서 하나 이상의 요청을 하나의 쓰레드로 한다기보다는 소수의 쓰레드로 처리한다는게 맞는 말 인것 같아요ㅎㅎ 보다 더 정확히 말하면 스프링에서 디폴트로 제공하는 워커 쓰레드의 수는 서버의 코어수 입니다 감사합니당😊 2019.08.12 18:45 신고
  • 프로필사진 Sanse 좋은 내용 잘 정리해주셔서 감사합니다. 2019.08.12 11:20
  • 프로필사진 AlwaysPr ㅎㅎ 이런 댓글이 동기부여가 되네요 감사합니당 2019.08.12 18:46 신고
  • 프로필사진 GiraffeB 좋은 내용 잘 봤습니다. 2019.09.04 23:06 신고
  • 프로필사진 Good 좋은 내용 잘봤습니다. 2019.09.06 08:43
  • 프로필사진 Good WebFlux에 대해 많이 들어보긴 했는데, 개념이 명확하진 않았습니다.
    근데 이 글을 보니까 개념에 대해서 확실하게 잡혀서 감사합니다.
    거기다가 뒤쪽에 WebFlux와 기존의 Servlet 기반의 Spring MVC를
    각각 어떤 경우에 사용해야 하는지,
    어떤 경우에 더 이득이 있는지 글을 보니까
    회사에서 어떤 경우에 적용하면 좋을지도 정리되어 무척 좋았습니다.
    좋은 정보 감사합니다.
    2019.09.07 11:22
  • 프로필사진 AlwaysPr 도움이 되셨다니 정말 다행입니다. ㅎㅎ
    요즘 통 블로그를 못 썼는데 덕분에 동기부여가 되네요. 회사에서 쓰게 되신다면 후기도 부탁드립니다! 감사합니다.
    2019.09.08 14:36 신고
  • 프로필사진 rest 좋은 글 감사드립니다!
    blocking i/o 예시로 작성하신 메소드 blocking() 를 그대로 테스트할 경우,
    캐시에 의해 9.xx초가 아니라 3.xx초가 나옵니다.
    헤더에 캐시를 제외해야 함을 추가해주시면 더 좋을 것 같아요!

    2019.09.16 15:39
  • 프로필사진 AlwaysPr 도움이 되었다니 다행입니다 ㅎㅎ
    혹시 캐시라함은 어떤 캐시를 말씀하시는지... 구체적으로 말씀해주시면 도움이 될 것 같네요 ㅎㅎ
    제가 작성해놓은 테스트코드는 예상대로 동작이되는데... 테스트코드를 통해서 확인해보시면 좀 더 도움이 될 것 같습니다.
    감사합니다.
    2019.10.29 21:54 신고
  • 프로필사진 김원태 오늘 하루 종일 block non-block , sync async 관련해서 파면서 정리하고있었는데 ㅎㅎ 검색하다가 좋은 글 보고 갑니다
    감사합니다.
    2019.09.18 19:42
  • 프로필사진 AlwaysPr 감사합니당 ㅎㅎ 2019.10.29 21:54 신고
  • 프로필사진 바지년 필요한 이유를 기반으로 글을 작성해주시니 독자 입장에선 술술 읽히네요. 감사합니다. 2019.10.28 00:15
  • 프로필사진 AlwaysPr 감사합니다 더좋은 글로 찾아뵙겠습니다! 2019.10.29 21:56 신고
  • 프로필사진 WEBBY 좋은 글 감사드립니다. 그런데 궁금한점이 webflux 구조 그림에서 register callback을 intensive operation에 등록하고 완료되면 eventloop가 request handler에게 trigger callback을 한다는게 이해가 잘안되는데요. 여기서 말하는 콜백은 각각 다른 콜백을 말하는건가요?

    그리고 그림에는 event loop가 싱글쓰레드라고 되어있는데 설명에는 worker thread가 cpu 코어 수만큼이라고 되어있는데 이 부분도 헷갈립니다 ㅎ
    2019.10.28 15:38
  • 프로필사진 AlwaysPr 서사적으로 작성하면 도움이 될까해서 적어보겠습니당.

    requests -> event loop -> register callback -> intensive operation(worker thread ...) -> operation complete -> event loop -> trigger callback(response)

    event loop는 단순히 request, response만 처리해준다고 보시는 편이 이해하기 쉬운것 같습니다.
    그래서 event loop가 intensive operation(worker thread)에게 callback을 등록하고 작업이 끝나면 event loop가 client에게 응답을 주는 것을 trigger callback이라고 표현한 것 같습니다.

    그리고 event loop랑 worker thread는 별개 이기 때문에 thread 수는 상이할 수가 있습니다.
    감사합니다 :)
    2019.10.29 22:07 신고
  • 프로필사진 WOW 좋은글 감사합니다.
    그런데 node.js의 비동기처리 방식과 비슷한 처리를 스프링 webflux에서 한다고 이해해도 될런지요?
    2019.10.31 09:48
  • 프로필사진 AlwaysPr 네넵 ㅎㅎ 맞습니다 2019.10.31 09:52 신고
  • 프로필사진 TB I/O개념부터 시작해서 webflux까지 이렇게 글/그림 적절히 넣으면서 자세히 써놓은 글은 간만에 보는것 같습니다.
    좋은글 감사드립니다.ㅎㅎ
    근데 보다보니 궁금한게 생겨서리....

    요청Queue+스레드풀 방식(A방식)과 비동기+NIO방식(B방식) 성능 차이나는 이유를 잘 모르겠습니다;;
    B방식도 다수의 클라이언트요청이 들어오는 족족 이벤트스레드가 워크스레드(CPU코어수)에 할당해 처리하는것 같공
    A방식도 일단 요청큐에 넣어놨다가 스레드풀에 할당해주는것 같공...

    어차피 A방식의 스레드풀에 스레드수가 4개고 B방식의 워크스레드수가 4개면 동시 처리갯수는 같은게 아닌가하는?
    (B방식에서는 ThreadPool Hell위험이 없는건가용?)



    A방식에서 요청큐에 받아 스레드풀중 한넘에게 할당하는것만 별도 스레드가 처리한다고 하면 A방식 B방식 같은건가용?

    아직 잘 이해를 못해서 그런지...
    한가르침 부탁드립니다. ㅠ.ㅠ
    2019.12.24 13:23
  • 프로필사진 AlwaysPr webflux, webmvc 작업들이 CPU 작업들이면 성능은 크게 다르지 않을 것으로 보입니다. 그러나 IO 연산(Network, DB 등)이 포함되어있다면 webflux에서는 NIO를 활용할 수 있어 좀 더 나은 성능이 나올 수 있을 것으로 보이네요. 2019.12.25 13:14 신고
  • 프로필사진 데르벨준 와...
    명쾌하고 탄탄한 글을 본게 정말 오랜만이네요
    머리에 바로 들어오는 글이었습니다
    2020.01.04 16:21
  • 프로필사진 Jay 글을 정말 잘쓰셨네요! webflux를 이해하는데 많은 도움이 되었습니다. 2020.01.16 17:40
  • 프로필사진 안녕하세요 글 보다가 궁금증이 생겨 문의 드립니다. 먼저 좋은글 감사합니다.

    위에 로직대로라면 webclient 사용시 한 스레드가 여러 요청에 대해서 처리를 할수 있는걸로 보이는데요. 워커가 2개여도 8개의 요청을 보냈을 경우 바로 즉각처리되고 이게 가능한 이유는 논블락킹으로 동작하면서 이벤트가 발생 되었을 경우(http요청에 대한 응답이 왔을 경우)에 클라이언트에 응답을 주면 되니 가능한 것이고요.

    그렇다면 앞단의 이벤트 루프가 모노 혹은 플럭스를 실행해서 이벤트가 발생할 수 있게 하고 이벤트가 발생햇을 경우에만 워커가 그 작업을 마저하는건가요?(http요청이라면 클라이언트에 대한 동작)

    디버깅을 해보면 모노나 플럭스를 서브스크립션 하는 주체는 워커로 보여서요.. 혼란스럽네요. 만약 서브스크립션 하는 주체가 워커라면 서브스크립션 한 워커가 그에 따른 이벤트를 끝까지 처리하게 되나요? 아니면 다른 스레드가 이벤트에 대해 처리할 수 있나요?
    결론은 워커들끼리 이런 이벤트를 받는 공간을 공유하는지 아니면 각각 워커전용 이벤트를 받는 공간이 별개인지 궁금합니다!
    2020.02.14 07:37
  • 프로필사진 Park.S.W 좋은 글 감사합니다..! webflux가 있다고해서 요즘 보고 있는데 개념이 잘 와닿지 않아 이해하는데 어려움이 있었는데, 머리속이 정리가 되는느낌입니다! 2020.03.23 10:14 신고
  • 프로필사진 호러블캣 정리가 너무 깔끔하고 훌륭합니다.
    잘 배우고 갑니다!
    2020.04.14 11:39
  • 프로필사진 수련생 재미있게 읽고 갑니다! 2020.04.23 20:06
  • 프로필사진 시루 집사 진짜 댓글을 안남길수가없는 명확한 글인것 같습니다 감사합니다!!!!!! 2020.05.27 02:34 신고
  • 프로필사진 우셜록 정리를 잘해주셔서 이해하는데 많은 도움이 되었어요, 감사합니다^^ 2020.06.01 23:50
  • 프로필사진 감동맨 너무 정리를 잘 한 것 같습니다. 감사합니다 2020.06.03 05:41
댓글쓰기 폼