Spring Webflux) Reactive Programming

Date:    Updated:

카테고리:

Reactive manifesto


reactive? (무언가를 바꾸거나 예방하기 위해) 먼저 행동하기보다는 사건이나 상황에 반응하는

Reactive manifestoReactive한 System을 만들기 위해서 필요한 구성요소, 갖춰야할 조건들을 알려주는 일종의 가이드라인이자 소프트웨어 아키텍처에 대한 선언문이다.


Reactive manifesto는 4가지의 핵심 가치를 제시한다.

Responsive(응답성)

Reactive manifesto 본문에는 Responsive에 대해 다음과 같이 적혀있다.

시스템이 가능한 한 즉각적으로 응답하는 것을 응답성 이 있다고 합니다. 응답성은 사용자의 편의성과 유용 성의 기초가 되지만, 그것뿐만 아니라 문제를 신속하 게탐지하고효과적으로대처할수있는것을의미합 니다. 응답성 있는 시스템은 신속하고 일관성 있는 응 답 시간을 제공하고, 신뢰할 수 있는 상한선을 설정하 여 일관된 서비스 품질을 제공합니다. 이러한 일관된 동작은 오류 처리를 단순화하고, 일반 사용자에게 신 뢰를 조성하고, 새로운 상호작용을 촉진합니다.

본문을 토대로 다음과 같이 정리할 수 있다.

  • 요구사항
    • 문제를 신속하게 탐지하고 효과적으로 대처해야한다.
    • 요청에 대해 신속하고 일관성 있는 응답 시간을 제공해야 한다.
    • 신뢰할 수 있는 상한선을 설정하여 일관된 서비스 품질을 제공해야 한다.
  • 요구사항들을 반영하였을 때 결과
    • 가능한 한 즉각적으로 응답가능한 서버
    • 사용자의 편의성과 유용성의 기초가 된다.
    • 오류 처리를 단순화할 수 있다.
    • 일반 사용자에게 신뢰를 조성하고, 새로운 상호작용을 촉진한다.


결론: 응답을 빠르게 내리게끔 시스템을 구성하자.

Resilient(복원력)

Reactive manifesto 본문에는 Resilient에 대해 다음과 같이 적혀있다.

시스템이 장애에 직면하더라도 응답성을 유지 하는 것을 탄력성이 있다고 합니다. 탄력성은 고가용성 시스템, 미션 크리티컬 시스템에만 적용되지 않습니다. 탄력성이 없는 시스템은 장애가 발생할 경우 응답성을 잃게 됩니다. 탄력성은 복제, 봉쇄, 격리, 위임에 의해 실현됩니다. 장애는 각각의 구성 요소에 포함되며 구성 요소들은 서로 분리되어 있기 때문에 이는 시스템이 부분적으로 고장이 나더라도, 전체 시스템을 위험하게 하지않고 복구 할 수 있도록 보장합니다.각 구성 요소의 복구 프로세스는 다른(외부의) 구성 요소에 위임되며 필요한 경우 복제를 통해 고가용성이 보장됩니다. 구성 요소의 클라이언트는 장애를 처리하는데에 압박을 받지 않습니다.

  • 요구사항
    • 복제, 봉쇄, 격리, 위임에 의해 실현되어야 한다.
    • 장애는 각각의 구성 요소에 포함 (봉쇄)
      • 구성 요소란 시스템을 구성하는 각각의 컴포넌트를 의미함
      • 구성 요소끼리 장애를 공유하지 않는다.
    • 구성 요소들은 서로 분리 (격리)
      • 격리된 상태여야 전체 시스템을 위협하지 않음
    • 각 구성요소의 복구 프로세스는 다른(외부의) 구성 요소에 위임 (위임)
    • 필요한 경우 복제를 통해 고가용성을 보장해야 한다. (복제)
  • 요구사항들을 반영하였을 때 결과
    • 장애에 직면하더라도 응답성을 유지할 수 있다.
    • 시스템이 부분적으로 고장이 나더라도, 전체 시스템을 위험하게 하지 않고 복구 할 수 있도록 보장할수 있다.
    • 구성 요소의 클라이언트는 장애를 처리하는데에 압박을 받지 않는다.


결론: 장애에 직면하더라도 각각의 구성요소들을 통해 응답성을 유지할수 있게끔 시스템을 구성하자.

Elastic(유연성)

Reactive manifesto 본문에는 Elastic에 대해 다음과 같이 적혀있다.

시스템이 작업량이 변화하더라도 응답성을 유지하는 것을 유연성이라고 합니다. 리액티브 시스템은 입력 속도의 변화에 따라 이러한 입력에 할당된 자원을 증가시키거나 감소키면서 변화에 대응합니다. 이것은 시스템에서 경쟁하는 지점이나 중앙 집중적인 병목 현상이 존재하지 않도록 설계하여, 구성 요소를 샤딩하거나 복제하여 입력을 분산시키는 것을 의미합니다. 리액티브 시스템은 실시간 성능을 측정하는 도구를 제공하여 응답성 있고 예측 가능한 규모 확장 알고리즘을 지원합니다. 이 시스템은 하드웨어 상품 및 소프트웨 어 플랫폼에 비용 효율이 높은 방식으로 유연성을 제공합니다.

  • 요구사항
    • 경쟁하는 지점이나 중앙 집중적인 병목 현상이 존재 하지 않도록 설계해야 한다.
    • 구성 요소를 샤딩하거나 복제하여 입력을 분산시켜야 한다.
    • 실시간 성능을 측정하는 도구를 제공해야 한다.
    • 응답성 있고 예측 가능한 규모 확장 알고리즘을 지원해야 한다.
  • 요구사항들을 반영하였을 때 결과
    • 작업량이 변화하더라도 응답성을 유지할 수 있다.
    • 입력 속도의 변화에 따라 이러한 입력에 할당된 자원을 증가시키거나 감소시킬 수 있다.
    • 상품 및 소프트웨어 플랫폼에 비용 효율이 높은 방식으로 유연성을 제공한다.


결론: 작업량에 상관없이 일관성 있는 응답성을 유지할 수 있게끔 시스템을 구성하자.

Message Driven(메세지 기반)

Reactive manifesto 본문에는 Message Driven에 대해 다음과 같이 적혀있다.

리액티브 시스템은 비동기 메시지 전달에 의존하여 구성 요소 사이에서 느슨한 결합, 격리, 위치 투명성을 보장하는 경계를 형성합니다. 이 경계는 장애를 메시지로 지정하는 수단을 제공합니다. 명시적인 메시지 전달은 시스템에 메시지 큐를 생성하고, 모니터링 하며 필요시 배압을 적용함으로써 유연성을 부여하고, 부하 관리와 흐름제어를 가능하게 합니다. 위치 투명 메시징을 통신 수단으로 사용하면 단일 호스트든 클러스터를 가로지르든 동일한 구성과 의미를 갖고 장애를 관리할 수 있습니다. 논블로킹 통신은 수신자가 활 성화가 되어 있을때만 자원을 소비할 수 있기 때문에 시스템 부하를 억제할 수 있습니다.

  • 요구사항
    • 비동기 메시지 전달에 의존해야 한다.
      • 즉, 구성요소 끼리 비동기적으로 메세지를 주고받으며 서로 독립적인 실행을 보장 해야한다.
    • 명시적인 메시지 전달을 해야한다.
    • 위치 투명 메시징을 통신 수단으로 사용해야 한다.
      • 장애를 메세지로 지정해서 위치와 상관없이 동일하게 장애를 관리해야 한다.
      • 각각의 구성요소를 독립적으로 확장 가능하게 만들고, 구성 요소를 더 쉽게 추가하거나 제거해야 한다.
    • 논블로킹 통신을 해야한다.
  • 요구사항들을 반영하였을 때 결과
    • 구성 요소 사이에서 느슨한결합, 격리, 위치 투명성을 보장하는 경계를 형성하고 이 경계는 장애를 메시지로 지정하는 수단을 제공한다.
    • 시스템에 메시지 큐를 생성하고, 모니터링하며 필요시 배압을 적용할 수 있다.
    • 유연성을 부여하고, 부하 관리와 흐름제어를 가능하게 한다.
    • 단일 호스트든 클러스터를 가로지르든 동일한 구성과 의미를 갖고 장애를 관리하게 된다.
    • 수신자가 활성화가 되어 있을때만 자원을 소비할 수 있기 때문에 시스템 부하를 억제할 수 있다.


결론: 비동기 통신 기반의 메세지 큐를 사용해서 통신하게끔 시스템을 구성하자.

정리


  • 핵심 가치: 가능한 즉각적으로 응답해야 한다.
  • 형태: 장애에 직면하더라도/작업량이 변화하더라도 응답성을 유지해야 한다.
  • 구성하기 위한 방법: 각 구성요소 끼리 비동기 non-blocking 기반의 메시지큐를 사용해서 통신해야 한다.

Reactive한 Programming

일반적인 서비스


  • 일반적인 서비스에서 구성 요소 혹은 객체는 다른 객체를 직접 호출하고 데이터를 받는다.
    • 동기적으로 직접 데이터를 주고받는다.
    • 만약 B나 C에서 응답을 받지 않는다면?
    • 특정 객체에 너무 많은 요청을 한다면?
  • 이 과정에서 장애가 전파됨으로써 경계가 무너지고 구성 요소의 독립적인 실행이 보장되지 않으며 복원력, 유연성 모두 위협 받게된다.


  • 구성요소는 서로 비동기적으로 메세지를 주고 받으며 독립적인 실행을 보장한다.
    • callercollect를 통해서 값을 조회해야 한다. callercallee동기적으로 동작한다.
  • 메세지 큐를 생성하고 배압을 적용하여 부하를 관리하고 흐름을 제어한다
    • stream이 메세지 큐의 역할을 하지만 부하를 관리할 수 없다.


일반적인 동기 기반의 서비스로는 Reactive manifesto 개념을 적용하기는 힘들다.

비동기 future 서비스


  • calleecaller에게 응답이 아닌 future를 제공한다.
  • callee는 각각의 값을 future를 통해서 전달한다.
  • caller는 해당 future를 chaining 하여 이를 처리한다.

  • 구성요소는 서로 비동기적으로 메세지를 주고 받으며 독립적인 실행을 보장한다.
    • -> callercallee비동기적으로 동작한다
  • 메세지 큐를 생성하고 배압을 적용하여 부하를 관리하고 흐름을 제어한다
    • -> future의 한계(한번에 값을 전달 해야함)때문에 메세지 큐의 역할을 할 수 없다.
    • -> 메세지 큐를 아예 쓰지 않기 때문에 부하를 관리할 수 없고 배압 또한 적용할 수 없다.


비동기적으로 동작한다는 점에서 일반적인 서비스 보다 나은면이 있지만 아직도 Reactive manifesto 개념을 제대로 대입하기는 힘들다.

Reactive streams

  • calleecaller 에게 응답이 아닌 publisher를 제공한다.
  • callee는 각각의 값을 publisher를 통해 전달한다.
    • publisher가 일종의 메세지 큐 역할을 하는 셈
  • caller는 해당 publishersubscribe 하거나 다른 caller에게 전달한다.
  • callersubscriber를 등록하여 배압을 조절하여 처리 가능한 만큼만 전달 받을수 있다.
    • publisher 에게 처리 가능한 만큼만 데이터를 요청
  • 구성요소는 서로 비동기적으로 메세지를 주고 받으며 독립적인 실행을 보장한다.
    • -> calleepublisher를 반환하고 callersubscriber를 등록한다.
    • -> 이 과정에서 callercallee는 비동기적으로 동작한다.
  • 메세지 큐를 생성하고 배압을 적용하여 부하를 관리하고 흐름을 제어한다
    • -> publisher는 메세지 큐를 생성해서 부하를 관리하고 흐름을 제어한다.
    • -> 배압을 조절할 수 있는 수단을 제공한다.
  • 비동기 데이터 stream을 사용하는 패러다임
  • 데이터의 전달, 에러, 완료 모든 것이 이벤트로 구성되고 이벤트를 통해서 전파되어야한다.(event-driven)


Reactive manifesto의 응답성, 복원력, 유연성, 메세지기반 개념이 모두 해당된다!

event-driven vs message-driven

Reactive manifesto에서는 구현 방법으로써 message-driven을 강조했는데 위에서 Reactive manifesto 개념들을 대입한 Reactive Programming 에서는 왜 event-driven을 강조할까? 서로 다른것인가?

  • message-driven
    • messageevent, command, query 등 다양한 형태를 수용한다.
    • message-drivenevent, command, query 등 다양한 형태의 메세지를 비동기적으로, 가능하다면 배압을 적용하여, 전달하는 형태에 집중한다.
  • event-driven
    • event-driven은 message의 형태를 event로 제한한다.
    • completion, error 심지어 값까지도 이벤트 형태로 전달한다.

결국 event-drivenmessage-driven의 하나의 일종이다.

따라서 Reactive programmingReactive manifesto의 원칙을 지킨다고 볼 수 있다.

📣 Reference

패스트캠퍼스 - Spring Webflux 완전정복 : 코루틴부터 리액티브 MSA 프로젝트까지

댓글남기기