ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • WebClient 와 WebFlux (정리중..)
    Back-End/Spring 2023. 6. 13. 00:19

     

    Java REST API Client Library 에는 여러가지 종류가 있다.

     

    - HttpURLConnection
    OKHttp, Retrofit, Volley
    HttpClient
    RestTemplate
    WebClient

     

    WebClient 이전에는 RestTemplate 와 HttpClient 를 많이 쓰다가 (사실 나는 RestTemplate 도 안 써본 것 같다)

    WebFlux 가 등장하면서 WebClient 를 사용하게 되었다.

     

     

    1. HttpURLConnection
    기본 JDK에 포함 (java.net)
    URLConnection을 구현한 클래스

    [  장점  ]
    - HTTP 프로토콜 이외에도 사용 가능
    - 속도가 빠르다.
    [  단점  ]
    - 코드가 복잡하다.
    - 타임아웃을 설정할 수 없다.
    - 쿠키 제어 불가능


    2. OKHttp/Retrofit/Volley
    안드로이드 HTTP 라이브러리

    3. HttpClient
    - Apache에서 제공 (org.apache.http)

    [  장점  ]
    - HttpURLConnection 에 비해 다양한 API를 지원한다.
    - 타임아웃 설정 가능
    - 쿠키 제어 가능
    [  단점  ]
    - 응답의 컨텐츠타입에 따라 별도 로직이 필요


    4. RestTemplate
    Spring 3.0 부터 지원 (org.springframework.http.client)
    HTTP 통신에 사용하는 템플릿
    주로 Blocking I/O 기반의 Synchronous API 로 사용

    [  장점  ]
    - HTTP 서버와의 통신을 단순화
    - RESTful 원칙을 지킨다.
    - json, xml 응답을 쉽게 받는다. (HttpMessageConverter 동작 : @RequestBody, @ResponseBody)
    [  단점  ]
    - Spring 5.0 까지는 유지되지만 향후 Deprecated 될 예정


    5. WebClient
    - HTTP Request를 수행하는 Client
    Reactor 기반의 Functional, Fluent API
    비동기 로직의 선언적 형태로 사용이 가능하다.
    완벽한 논블록킹 형태이며, 스트리밍을 지원한다.
    서버 사이드의 request/response를 인코딩, 디코딩하는 코덱들을 다 지원한다.

    HTTP Protocol (Hypertext Transfer Protocol)

    두 컴퓨터 간의 통신 프로토콜
    Stateless

     

    HTTP 이외의 프로토콜도 존재한다.

    SMTP Protocol (Simple Mail Transfer Protocol)
    이메일을 보내기 위해 이용되는 프로토콜
    모든 문자가 7bit ASCII로 되어있어야 한다고 규정

     


    1. HTTP Request를 수행하는 Client


    2. Reactor 기반의 Functional, Fluent API

    Reactor ?
    - Reactive 라이브러리
    Reactive ?
    - 반응형
    - 데이터가 변경 될 때 마다 이벤트를 발생시켜서 데이터를 계속적으로 전달


    3. 비동기 로직의 선언적 형태로 사용이 가능하다.

    선언적 형태
    명령적 언어: C, C++, Java
    선언적 언어: SQL, HTML


    명령형
    - 어떤 방법(How)으로 할 것인가

    - 내부 로직에 for 문을 추가하여 직접 명령을 내린다.
    public static void toUpper(List<String> list) {
    	for (int i=0; i<list.size(); i++) {
    		list.set(i, list.get(i).toUpperCase());
    	}
    }

    선언형
    - 무엇(What)을 할 것인가

    - 내부 로직이 어떻게 동작하는지 알 필요 없이 선언만 해주면 된다.
    public static void toUpper(List<String> list) {
    	list.stream().map(String::toLowerCase);
    }​

    함수형이란 input 에 대해 똑같은 output 을 return 해준다는 것을 의미한다.

     


    Synchronous/Asynchronous

    • 시작 시간 또는 종료 시간이 일치
    • A,B 쓰레드가 동시에 작업 시작하면 동기
    • 메소드 리턴 시간(A)과 결과 시간(B)이 일치하면 동기
    • A가 끝나는 시간과 B가 시작하는 시간이 같으면 동기

    ※ 비동기는 서비스 실행 후, 리턴 시점과 결과를 받는 시점이 다르다.



    Blocking/Non-blocking

    • 제어할 수 없는 대상을 컨트롤하는 방법
    • 대상이 제한적
    • IO


    4. 완벽한 논블록킹 형태이며, 스트리밍을 지원한다.

    Publisher 구현체

    • Mono : 0~1 개의 응답 생성
    • Flux : n 개의 응답 생성

     

    발행&구독 패턴
    하나의 요청이 들어왔을 때 blocking 상태라면 요청이 끝날 때까지 다른 요청이 들어올 수 없다.
    그래서 등장한 방법이 asynchronous 이다.
    비동기 요청은 작업이 완료될 때까지 기다리지 않고 곧바로 다음 요청으로 넘어가기 때문에 blocking 없이 새로운 작업을 수행할 수 있다.

    이 비동기 요청을 처리하기 위해 필요한 것이 스레드이다.
    스레드는 운영 체제가 프로그램 내부의 여러 동작을 병렬로 처리할 수 있도록 하는 방법이다.

    하지만 이것 역시 단점이 있다.
    HTTP 프로토콜은 stateless 하여 상태를 갖지 않기 때문에 요청과 응답을 받을 때에 서로를 알고 있어야한다.
    그렇지 않으면 A의 요청에 대해 B의 응답을 받는 불상사가 발생한다.

    그래서 등장한 것이 publisher/subscriber 패턴이다.
    이 패턴은 publisher/subscriber 사이에 broker 가 존재하여 알아서 처리를 해준다.
    들어온 요청을 이벤트 루프에 차곡차곡 쌓아서 순차적으로 처리하는 방식이다.
    장점은  비동기라는 것이고, 단점은 큐이기에 데이터가 많아지면 응답이 늦어진다는 점이다.

    그림은 아래와 같다.

    https://www.baeldung.com/spring-webflux-concurrency

     

    Q. 그렇다면 데이터베이스에 접근할 때에는 문제가 생기지 않나?

    A. 관계형 데이터베이스일 경우에는 생길 수 있다. 하지만 문제가 생기지 않게 할 수 있는 방법이 있다.

    그래서 등장한 것이 Non-blocking 드라이버를 제공하는 데이터베이스들이다.

    예시로 Reactive mongodb 나 Reactive Redis, R2DBC 가 있다.

    이것들 역시 이벤트 루프에 요청을 순차적으로 쌓아두고 하나씩 처리하는 방식을 제공하고 있기 때문에 blocking 을 걱정할 필요가 없다.

    (NoSql 의 경우에는 테이블 구조가 없고, 비관계형이기 때문에 문제 발생이 적다 뿐이지 blocking 일 경우 문제가 아주 없다는 의미는 아니다. 안전하게 사용하려면 non-blocking 드라이버가 지원되는지 확인해야한다.)


    5. 서버 사이드의 request/response를 인코딩, 디코딩하는 코덱들을 다 지원한다.

    MVC 방식 (어노테이션을 의지한 개발)

    1. 요청 매핑
    웹요청을 어느 핸들러에게 보낼지 결정
    url 헤더, 리퀘스트 맵핑
    2. 요청 바인딩
    핸들러에 전달할 웹 요청 준비
    웹url, 헤더, 쿠키, 바디(자바 오브젝트 형태로 변환하여 전달)

    3. 핸들러 실행
    전달 받은 요청 정보를 이용해 로직을 수행하고 결과를 리턴
    4. 핸들러 결과처리, 응답 생성
    - 핸들러의 리턴 값으로 웹 응답생성

     

    함수형 모델 (RouterFunction, handlerfunction)

    1. 새로운 요청&응답 모델
    - 추상화한 새로운 모델
    - serverRequest/serverResponse
    2. 서블릿 스택 과 서블릿 API 에서 탈피
    - 리액티브 스택
    - 호환성은 가지고 있지만 비권장

    3. 지원 웹서버/컨테이너
    - 서블릿3.1+, : 비동기&논블로킹 요청 처리 기능 사용
    - 네티
    - undertow: 비동기&논블로킹 IO 웹서버 (과거에는 톰캣, 제티 등)

     

     

     

     

    더보기

    참고 자료 출처

    - https://www.baeldung.com/spring-webflux-concurrency

    - https://www.youtube.com/watch?v=2E_1yb8iLKk&t=6s

    - 어떤 블로그 보고 많이 배웠는데 링크를 잃어버렸다... 나중에 찾으면 추가할 예정...

    +) 참고를 바탕으로 제가 이해한 바를 적었습니다.

     

    'Back-End > Spring' 카테고리의 다른 글

    [Spring] Singleton Pattern (정리중..)  (0) 2023.08.18
Designed by Tistory.