Reactive Programming - 특징

this-is-spear·2023년 3월 18일
0

문서의 내용이 많아 분리해서 관리하고 있습니다. 전체 내용은 링크를 통해서 확인할 수 있습니다.

Reactive Programming 의 기능

reactive libraries는 전통적인 비동기식 접근 방식의 단점을 해결하는 동시에 아래의 특징을 제공한다.

  • Composability and readability
  • Data as a flow manipulated with a rich vocabulary of operators
  • Nothing happens until you subscribe
  • Backpressure or the ability for the consumer to signal the producer that the rate of emission is too high
  • High level but high value abstraction that is concurrency-agnostic

위 내용을 요약하자면 아래와 같다.

  • 가독성과 여러 기능들을 제공해준다.
  • 백프레셔가 가능해 데이터의 흐름을 조절할 수 있다.
  • 동시성에 구애받지 않는 높은 수준의 추상화

Nothing happens until you subscribe

스트림에서 데이터를 가공하고 변경해도 구독하지 않으면 아무일도 일어나지 않는다.

1. Composability and Readability

composability란 multiple asynchronous task을 조율하는 기능을 의미한다. 이러한 기능을 이용해 (1)이전 작업의 결과를 feed 한 다음, 후속 작업에서 사용하거나 (2)fork-join 스타일로 여러 작업을 실행할 수 있다. 또한 상위 수준 시스템에서 비동기 작업을 재사용할 수 있다.

fork-join 스타일이 뭐지?

Java 7에 추가된 클래스이며 효율적으로 병렬처리 하기위해 작업을 여러 개로 나누어 계산한 후 결과를 모으는 작업을 의미한다.

하나의 작업 공간에서 모든 작업을 관리하면 경쟁상태가 발생하고, 작업 공간을 분리하면 오버헤드가 많아진다. 두 가지의 특성을 잘 조합해 전체 작업을 관리하는 공간과 스레드마다 적당한 작업 공간을 유지하며 효율적으로 작업을 처리한다.

스레드의 작업 공간이 비어 있을 경우 다른 스레드의 작업을 빼앗아서(Work Stealing) 진행해 작업을 더 효율적으로 진행한다.

비동기 프로세스 계층은 복잡하다.

작업을 조율하는 기능은 코드의 가독성 및 유지 관리 가능성과 밀접하게 연결되어 있다. 비동기 프로세스를 추가하게 되면 계층이 늘어나게 되고 복잡해져 개발 생산성이 확연하게 떨어진다.

콜백은 단순하지만 복잡해지면 더 어려워진다.

이전부터 자주 사용하던 콜백 모델은 단순하지만 주요 단점 중 하나는 복잡한 프로세스 경우 콜백에서 콜백을 실행해야 하고 그 자체가 다른 콜백 내부에 중첩되어야 한다는 것이다. 이러한 코드는 동작을 추론하기가 매우 어렵다.

따라서 Reactor는 좋은 선택이 될 수 있다!

Reactor는 중첩이 최소화되어 비즈니스 코드에 추상적인 구성을 반영하기 쉽고, 모든 기능을 동일한 계층으로 유지되는 풍부한 기능을 제공하고 있다!

2. The Assembly Line Analogy

Reactive application에서 처리되는 데이터를 assembly line을 통해 이동한다고 볼 수 있다. Reactor는 이벤트 루프에서 데이터를 전달하는 컨베이어 벨트이자 워크스테이션이다.

재료에서 제품이 되기까지 흐름을 공장처럼 생각해보자

  1. 공장(Reactor)은 소비자(Subscribe)에게 제품(Product)을 만들어 달라는 요청(Request)을 받는다.
  2. 공장(Reactor)은 공급자(Publisher)에게 원자재(task)를 납품받아 컨베이어 벨트(Workstation)에 올려 필요한 작업장(Workstation)에게 전달한다.
  3. 제품(Product)이 완성되면 소비자(Subscribe)에게 응답(Resposne)한다.
    2 번 단계에서 알 수 있듯이 원자재(task)는 여러 작업장을 거쳐 원자재를 가공(operator) 하거나 중간 조각을 함께 모아(zip) 다른 컨베이어 벨트(Event Loop)를 이룰 수 있다.

제일 중요한 건 받는 입장에서 흐름을 제어한다는 것

특정 지점에서 제품(Product)을 포장하는 데 오래 걸리는 경우 문제가 있는 작업장(Workstation)은 원료의 흐름을 제한하기 위해 상위 작업장(Workstation)에 신호를 보내 흐름을 제어할 수 있다.

3. Operators

Reactor에서 operators는 어셈블리 비유에서 workstation이다. 각 작업장(Workstation|Operator)은 다음 작업장(Workstation|Operator)에게 전달한 재료(task)를 만들 공급자(Publisher)에게 해야할 기능을 정의하고 만들 재료(task)를 위한 원자재(task)를 제공해주는 공급자(Publisher)를 새 인스턴스로 래핑한다. 즉, 동작은 다음과 같다.

  1. 원자재(task)를 제공해주는 공급자(Publisher)를 새 인스턴스로 래핑
  2. 작업장(Workstation|Operator)은 다음 작업장(Workstation|Operator)에게 전달한 재료(task)를 만들 공급자(Publisher)에게 해야할 기능을 정의

이렇게 전체 체인이 연결되어 데이터가 첫 번째 게시자에서 시작되고 체인 아래로 이동하며 변환된다.

작업장(Workstation|Operator)을 구성할 때 주의점은 다음과 같다.

  • 제일 중요한 건 구독자(Subscriber)가 게시자(Publisher)를 구독하기 전까지는 아무 일도 일어나지 않는다는 것이다. 연결이 되어도, 구독자(Subscriber)가 데이터를 받지 않으면 아무런 의미가 없다.
  • 작업장(Workstation|Operator)에서 새 인스턴스를 생성한다는 것을 이해하면 체인에서 사용한 작업장(Workstation|Operator)이 적용되지 않는다고 생각할 수 있고, 실수를 피하는 데 도움이 된다.

Reactor는 다양한 기능을 하는 작업장(Workstation|Operator)을 제공한다.

Reactor와 같은 반응성 라이브러리의 가장 큰 부가 가치 중 하나는 그들이 제공하는 풍부한 연산자 어휘다. 즉, 여려 기능을 제공하는 작업장(Workstation|Operator)을 제공한다. 이들은 간단한 변환 및 필터링에서 복잡한 조율 및 오류 처리에 이르기까지 많은 영역을 다룬다.

4. Nothing Happens Until You subscribe()

Reactor에서 Publisher 체인을 작성한다고 바로 데이터가 펌핑하지 않는다. 대신 비동기 프로세스에 대한 재사용성 및 구성에 도움이 될 수 있는 추상적 설명을 생성한다.

Reactor는 구독(subscribe)을 통해 데이터 흐름을 구독하는 구독자(Subscriber)에게 데이터를 제공하는 공급자(Publisher)를 연결하고, 완료됐다는 내부 신호에 의해 공급자(Publisher)로 다시 돌아간다.

주의할 점은 공급자(Publisher)가 보낸다고 해도 구독자(Subscriber)가 구독(subscribe)하지 않으면 데이터는 흐르지 않는다.

5. Backpressure

Propagating signals upstream는 backpressure를구현에도 사용하며, assembly lin 비유에서는 작업장이 상위 작업장보다 더 느리게 처리할 때, 상위 작업장으로 feedback 신호를 보낸다.

Reactive Streams Backpressure 메커니즘

Reactive Streams 사양에 의해 정의된 실제 메커니즘은 유추에 매우 가깝다.

  • 구독자(Subscriber)는 unbounded mode 에서 작업한다.
  • 가능한 한 가장 빠른 속도로 모든 데이터를 푸시한다.
  • 요청 메커니즘을 사용하여 최대 n개의 요소를 처리할 준비가 되었음을 소스에 알릴 수 있다.

버퍼링

구독자가 버퍼를 요청하면 소스에서 10개의 요소를 생성하는 것이 허용된다. 일부 operator는 미리 가져오는 전략을 이용해 또한 요청이 왕복되는 과정을 생략하거나 비용이 많이 들지 않는 경우 요청되기 전 요소를 생성한다.

이는 push 모델을 push-pull hybrid로 변환하며, 여기서 downstream은 즉시 사용할 수 있는 경우 upstream에서 n개의 요소를 pull 할 수 있다. 그러나 요소가 준비되지 않은 경우 생성될 때마다 업스트림에 의해 푸시된다.

6. Hot vs Cold

Reactive libraries의 Rx 계열은 reactive sequences의 두 가지 광범위한 범주인 hot과 cold를 구분합니다. 이러한 구분은 주로 reactive stream이 구독자(Sbuscriber)에게 반응하는 방식과 관련이 있다.

Cold sequence

Cold sequence는 데이터를 포함하여 각 구독자(Subscriber)마다 새로 시작된다. 예를 들어 데이터가 HTTP 호출을 래핑하는 경우 각 구독에 대해 새 HTTP 요청이 생성된다.

Hot sequence

Hot sequence는 각 구독자에 대해 처음부터 시작하지 않습니다. 오히려 늦은 구독자(Subscriber)는 구독한 후 방출된 신호를 받는다. 그러나 일부 hot reactive stream은 전체 또는 부분적으로 방출 기록을 캐싱하거나 리플레이할 수 있다.

일반적인 관점에서 Hot sequence는 수신하는 구독자(Subscriber)가 없을 때도 발생할 수 있지만 구독하기 전에는 아무런 일도 일어나지 않는다는 것에 유의하자.

Hotr과 cold에 대해서 자세하게 알고싶다면 해당 this reactor-specific section 글을 확인하자.

profile
익숙함을 경계하자

0개의 댓글