엄범

 

실전! 스프링 5를 활용한 리액티브 프로그래밍

 

왜 리액티브인가?

  • 전통적인 개발 방법대로 작성했을 때 발생했던 문제?
    • 시간 당 리퀘스트, 처리 시간, 스레드 수를 고려해서 초당 1000건 처리할 수 있을 거라고 가정하고 시스템을 작성했는데
    • 블랙 프라이데이 등 트래픽이 몰릴 시 응답 시간 증가 / 서비스 중단
  • 사용자 응답성에 영향을 미칠 수 있는 변화(갑작스러운 트래픽 변화 등)에 반응하기 위하여 만족해야 하는 것?
    • 탄력성(elasticity)
      • 요청이 많아지면 시스템 처리량이 자동으로 증가했다가, 요청이 감소하면 자동으로 감소
      • 수직적 또는 수평적 확장 ( Scale-Up, Scale-Out )
      • 하지만 이게 어려운 경우가 있음 ("6장 웹플럭스 - 비동기 논블로킹 통신"에서 다룬다)
    • 복원력(resilient)   {탄성(resiliency)}
      • 시스템의 한 부분에 장애가 발생해도 나머지 기능에는 문제가 없을 것
      • 시스템의 기능 요소를 격리해 모든 내부 장애를 격리하여 독립성을 확보함으로써 달성
      • 결제 서비스가 중단된 경우라도 일단 사용자 주문을 접수하고 이후 자동 재시도 하는 등
    • 이 두가지를 만족하기 위한 프로그래밍 패러다임이 바로 Reactive
  • 전통적인 개발 방법이 어떤 점에서 사용자 응답성에 불리한지는 아래에.

 

메시지 기반 통신
  • 보편적으로 스프링에서 HTTP를 이용해 컴포넌트 간의 통신을 수행하는 예제는 다음과 같다.
  • 하지만 RestTemplate은 Blocking I/O 기반의 API다. 그래서 getForObject를 호출하면 스레드A가 block된다.

  • 스레드를 여러개 띄워서 Blocking 되어 있는 동안 다른 스레드가 일하도록 하면 되는 것 아닌가?
    • Context Switching 비용 때문에 스레드를 무작정 많이 띄운다고 빨라지지는 않음
    • "6장 웹플럭스 - 비동기 논블로킹 통신"에서 다룬다
  • I/O 측면에서 리소스 활용도를 높이려면 비동기 논블로킹(async non-blocking) 모델을 사용해야 함
    • 현실에서 이런 종류의 커뮤니케이션은 문자 메시지
    • 분산 시스템에서도 서비스 간 통신에는 메시지 기반(message-driven) 통신 원칙을 따라야 함
      • 메시지 브로커(message broker)
    • 메시지 기반 통신을 사용하면 resiliency, elasticity가 향상됨
      • 한 수신 객체가 장애여도 다른 수신 객체가 메시지를 읽을 수 있으니 resiliency 향상
      • 메시지 대기열을 모니터링해 elasticity 제어 가능
      • "8장 클라우드 스트림으로 확장하기"에서 다룸

 

정리하면, 리액티브 시스템이란?
  • 분산 시스템으로 구현되는 모든 비즈니스의 핵심 가치는 응답성
  • 높은 응답성을 확보한다는 것은 곧 탄력성, 복원력을 가지고 있다는 것을 의미
  • 응답성, 탄력성, 복원력을 확보하기 위해 메시지 기반 통신을 사용
  • 리액티브 선언문  
    • 즉, 응답이 잘 되고, 탄력적이며 유연하고 메시지 기반으로 동작하는 시스템 입니다. 우리는 이것을 리액티브 시스템(Reactive Systems)라고 부릅니다.
      • 사실 응답성, 탄성력, 복원력을 확보하기 위한 가장 핵심적인 개념은 BackPressure라고 생각함.
      • 단순히 메시지 기반 통신을 쓴다고 해서 다 Reactive는 아니니까.

 

왜 리액티브 스프링인가?

  • 지금까지는 시스템, 아키텍쳐 관점에서의 리액티브 시스템에 대해서 얘기한 반면, 구현 관점에서의 프로그래밍 기술로서의 리액티브 프로그래밍도 있음
  • "큰 시스템은 더 작은 규모의 시스템으로 구성되기 때문에 구성 요소의 리액티브 특성에 의존합니다. 즉, 리액티브 시스템은 설계 원칙을 적용하고, 이 특성을 모든 규모에 적용해 그 구성 요소를 합성할 수 있게 하는 것을 의미합니다."
    • 따라서 구성 요소 수준에서도 리액티브 설계 및 구현을 제공하는 것이 중요
    • 결국 리액티브 프로그래밍을 통해 리액티브 시스템을 작성해야 함

 

서비스 레벨에서의 반응성
  • 전통적인 방식인, 명령형 프로그래밍(imperative programming) 방식
    • imperative
    • `` calculate()`` 메서드에서 스레드가 blocking된다는 문제가 있음
    • 위에 서술했듯 스레드가 blocking 된다고 추가적인 스레드를 만드는 것은 리액티브 시스템의 관점이 아님
  • 콜백(callback) 방식
    • callbacks
    • `` SyncShoppingCardService``는 동기식이라 성능상 별 이점은 없음. 어차피 람다를 넘겨도 메서드 내에서 blocking이 걸릴 테니까
    • `` AsyncShoppingCardService``는 비동기식이라 별도 스레드에서 요청을 처리하게 됨
    • 이러한 콜백 방식의 장점은 동기,비동기 상관 없이 컴포넌트가 콜백 함수에 의해 분리된다는 것에 있음
      • 응답 이후 작업을 callback 람다로 넘겨 관심사를 분리
      • `` calculate()`` 자체는 void를 리턴하므로 클라이언트 메서드에서는 리턴값과 상관 없이 이후 로직을 작성할 수 있음
    • 하지만 콜백 지옥을 피할 수 없음
  • `` Future``를 사용하는 방식
    •  Futures
    • `` Future<>``를 반환함으로써 callback 지옥에 빠지지 않을 수 있음
      • callback 지옥? "리턴값이 필요해서 callback 안에 callback..."
    • 하지만 필요한 결과를 얻으려 ``java future.get()``를 호출하여 외부 실행과 동기화해야 함
      • 이 때 준비가 안되었다면 blocking이 발생할 수 있음
  • `` CompletableFuture``를 사용하는 방식
    • completion_stage
    • 괜찮은 방법이지만, 몇 가지 부족한 점이 있음
    • Spring 4 MVC에서는 JDK8부터 제공되는 `` CompletionStage`` 대신, 그 역할을 하는 `` ListenableFuture``를 자체적으로 제공했음 (하위 호환성 때문)
      • spring_futures
      • 스프링은 블로킹 네트워크 호출을 별도의 스레드로 래핑함
        • 비동기로 만들기 위해 래핑한다는 의미인 것 같음. ==> 진짜 async가 아니다.
      • *** Spring 5에서는 `` WebClient``가 도입되어 논블로킹 통신을 지원하고 있음.
  • 이러한 문제점들 때문에 스프링에서 리액티브 프로그래밍 지원을 위한 새로운 모듈을 구현하기로 했음. (이후 챕터에서 소개)

 

리액티브 프로그래밍의 단점?

  • 공통적으로 얘기하고 있는 것이, "문제가 발생했을 때 코드 추적이 어렵다"는 것
    • 해당 이벤트를 구독하고 있는 observer들을 다 뒤져봐야 할 수도 있음
    • 반대로 해당 이벤트를 발행하는 subject들을 다 뒤져봐야 할 수도 있고

 

리액티브 라이브러리 추상화 수준 정리

LINK

  • Reactive Streams는 back pressure를 사용하는 async component 사이의 interaction을 정의하는 small spec이다.
    • 너무 low-level이라 application API로서는 유용하지 않음.
    • 그래서 나온 것이 reactive library.
  • Reactor는 reactive library다.
    • Mono와 Flux API 및 다양한 operator를 지원함.
    • reactive stream 기반의 library니까, 모든 operator는 non-blocking back pressure를 지원함.
    • 또 다른 reactive library로는 RxJava 등이 있음.
  • Spring WebFlux는 Reactor를 코어 디펜던시로 사용함.
    • 하지만 Reactive Streams기반의 다른 reactive library와도 상호 작용 가능하긴 함.