리액티브 선언문

용어집

비동기

옥스퍼드 사전은 비동기를 _"동시에 존재하거나 발생하지 않는"_ 이라고 정의한다. 이 선언문의 문맥에서는 클라이언트에서 서비스로 전송된 요청이 이후 임의의 시점에 처리된다는 의미이다. 클라이언트는 서비스 내에서 실행되는 것을 직접 보거나 동기화할 수 없다. 이것은 서비스가 요청에 대한 처리를 마쳐야만 클라이언트가 재개되는 동기화 처리의 반대말이다.

배압(Back-Pressure)

한 컴포넌트가 부하를 이겨내기 힘들 때, 시스템 전체가 합리적인 방법으로 대응해야 한다. 과부하 상태의 컴포넌트에서 치명적인 장애가 발생하거나 제어 없이 메시지를 유실해서는 안 된다. 컴포넌트가 대처할 수 없고 장애가 발생해선 안 되기 때문에 컴포넌트는 상류 컴포넌트들에 자신이 과부하 상태라는 것을 알려 부하를 줄이도록 해야 한다. 이러한 배압은 시스템이 부하로 인해 무너지지 않고 정상적으로 응답할 수 있게 하는 중요한 피드백 방법이다. 배압은 사용자에게까지 전달되어 응답성이 떨어질 수 있지만, 이 메커니즘은 부하에 대한 시스템의 복원력을 보장하고 시스템 자체가 부하를 분산할 다른 자원을 제공할 수 있는지 정보를 제공할 것이다. 탄력성 (확장성과 대조) 참조.

일괄 처리(Batching)

현대 컴퓨터는 같은 작업의 반복 실행하는 것에 최적화되어 있다. 명령어 캐시 및 분기 예측은 같은 클록 주파수에서 초당 처리 할 수 있는 명령 수를 증가시켰다. 즉, 한 CPU 코어에 여러 다른 작업을 동시에 실행하는 것은 한 작업을 실행하는 경우에 달성할 수 있는 최대 성능의 이점을 취할 수 없다는 것이다. 가능하면 여러 작업 간에 실행 전환이 적도록 프로그램을 구성해야 한다. 이는 일괄적으로 데이터 묶음을 처리하거나 전용 하드웨어 스레드들이 각각 서로 다른 작업을 수행하는 것을 의미한다.

동기화와 조정이 필요한 외부 자원 의 사용에도 같은 논리가 적용된다. 영구 저장장치가 제공하는 입출력 대역폭은 모든 코어에서 경쟁하는 대신 단일 스레드(CPU 코어)에서 명령을 실행할 때 크게 향상될 수 있다. 단일 진입점을 사용하는 것은 장치의 접근 패턴에 맞게 최적화되어 명령들이 재정렬 될 수 있다는 장점도 있다(현대 저장 장치들은 임의 접근보다 선형적인 접근에서 성능이 향상된다).

추가로 일괄 처리는 입출력이나 고비용의 연산과 같은 비용이 큰 명령들의 비용을 나눌 기회를 제공한다. 예를 들어 효율성을 증가시키고 사용률을 감소시키기 위해 같은 네트워크 패킷이나 디스크 블록에 여러 데이터 항목을 묶어서 넣을 수 있다.

컴포넌트

우리가 설명하는 것은 고전적인 모듈 형 소프트웨어 아키텍처이다 (Parnas (1972) 참조). 우리는 "컴포넌트"라는 용어가 "구획"에 가까우므로 사용하고 있다. 이는 각 컴포넌트가 독립적이고 캡슐화되어 다른 구성 요소와 분리 (그리고 억제)됨을 의미한다. 이 개념은 시스템의 실행시간 특성에 가장 많이 적용되지만, 일반적으로 소스 코드의 모듈 구조에도 반영된다. 서로 다른 컴포넌트가 공통된 작업을 수행하기 위해 같은 소프트웨어 모듈을 사용할 수는 있지만 각 컴포넌트의 최상위 동작을 정의하는 프로그램 코드는 자체 모듈로 되어있다. 컴포넌트 경계는 종종 문제 영역의 제한된 컨텍스트 에 밀접하게 부합한다. 이것은 시스템 설계가 문제 영역을 반영하는 경향이 있으므로 분리를 유지하면서 발전하기 쉽다는 것을 의미한다. 메시지 프로토콜은 제한된 컨텍스트 (컴포넌트) 간의 자연스러운 연결과 통신 계층을 제공한다.

위임

비동기으로 다른 컴포넌트에 작업을 위임하는 것은 작업이 다른 컴포넌트 의 컨텍스트에서 수행되는 것을 의미한다. 이 위임된 컨텍스트는 다른 오류 처리 컨텍스트, 다른 스레드, 다른 프로세스 또는 다른 네트워크 노드에서 실행될 수 있다. 위임의 목적은 작업의 수행 책임을 다른 컴포넌트에 넘기는 것으로 위임한 컴포넌트는 다른 처리를 수행할 수 있고 장애 처리 및 진행 보고와 같은 추가적인 일이 필요할 때 위임된 작업의 진행 상항을 관찰할 수도 있다.

탄력성 (확장성과 대조)

탄력성은 다양한 요구를 충족하기 위해 자원을 비례적으로 추가하거나 제거하여 시스템의 처리량이 자동으로 증가하거나 감소하는 것을 의미한다. 시스템은 실행시간에 자원을 동적으로 추가하거나 제거하여 이득을 볼 수 있도록 확장 가능해야 한다 (확장성 참조). 따라서 탄력성은 확장성에 자동 자원 관리 개념이 추가된 것이다.

장애 (오류와 대조)

장애는 서비스 내에서 발생하는 예기치 못한 상황으로 서비스의 정상적인 동작을 막는다. 장애 발생은 일반적으로 현재 이후의 모든 클라이언트 요청에 대한 응답을 막는다. 장애는 예상 가능하며 조건으로 처리되는 오류와 대조된다. 예를 들어 오류는 입력값 검증에서 발생할 수 있는데, 이는 클라이언트에 정상적인 처리 과정의 일부로 전달 된다. 장애는 예상할 수 없고 시스템이 같은 작동 수준으로 재개하려면 개입이 필요하다. 이것은 장애가 항상 치명적이라기보다는 장애 발생 이후 시스템의 가용 능력이 감소할 것이라는 뜻한다. 오류는 정상 작동의 예상되는 부분으로 즉시 처리되며 시스템은 오류가 발생한 후에도 가용 능력을 유지하여 작동한다.

장애의 예로는 하드웨어 오작동, 치명적인 자원 고갈로 인한 프로세스 종료, 내부 상태 오류를 발생시키는 프로그램 결함 등이 있다.

분리 (그리고 억제)

분리는 시간과 공간 모두에서 분리로 정의할 수 있다. 시간상의 분리는 송신자와 수신자가 독립적인 생명 주기를 가질 수 있음을 의미한다. 송신자와 수신자가 통신할 수 있기 위해서 동시에 존재할 필요는 없다. 이것은 메시지 기반(이벤트 기반과 대조)을 통해 컴포넌트 간에 비동기 경계를 추가하는 것으로 가능하다. 공간 분리 (위치 투명성(Location Transparency)으로 정의 됨)는 송신자와 수신자가 같은 프로세스에서 실행될 필요가 없다는 의미이다. 애플리케이션의 가동 중에 달라질 수는 있지만, 운영 부서나 실행시간에 자체적으로 정한 곳이 가장 효과적이다.

진정한 분리는 대부분의 객체 지향 언어에서 말하는 캡슐화의 개념을 뛰어넘으며 다음과 같은 분류와 방지를 제공한다 :

  • 상태와 동작 : 아무것도 공유하지 않는 설계를 가능하게 하고 경합과 일관성 비용을 최소로 한다 (에 정의).
  • 장애 : 장애 (오류와 대조)가 다른 컴포넌트들에 전파되는 것을 막고 미세한 수준으로 장애를 포착하고 알리며 관리할 수 있다.

컴포넌트 사이의 강한 분리는 잘 정의된 프로토콜을 사용한 통신을 기반으로 한다. 이것은 느슨한 결합을 가능하게 하고 시스템을 이해, 확장, 테스트, 발전하기 쉽게 한다.

위치 투명성

탄력성 (확장성과 대조) 시스템은 적응력이 있어야 하고 수요 변화에 지속해서 반응해야 하며 원활하고 효율적으로 규모를 확장하고 축소해야 한다. 이 문제를 대단히 단순화하는 핵심 통찰력은 우리가 모두 분산 컴퓨팅을 수행하고 있다는 것을 깨닫는 것이다. 단일 노드 (QPI 링크를 통해 통신하는 여러 독립 CPU 포함) 또는 노드 클러스터 (네트워크를 통해 통신하는 독립적인 시스템)에서 시스템을 실행하든 상관없다. 이 사실을 받아들인다는 것은 멀티 코어에서 수직으로 확장하거나 클러스터에서 수평으로 확장하는 것이 개념적으로 차이가 없다는 것을 의미한다.

모든 컴포넌트 가 이동성을 지원하고 로컬 통신이 최적화되어 있다면 시스템 토폴러지 및 배포 모델을 사전에 정의 할 필요가 없다. 우리는 이 결정을 운영자와 실행시간에 넘길 수 있다. 운영자는 시스템이 어떻게 이용되는지에 따라 시스템을 조정하고 최적화할 수 있다.

비동기 메시지 기반(이벤트 기반과 대조)로 활성화된 공간 분리 (분리 (그리고 억제) 정의 참조)와 실행시간 인스턴스의 참조 분리는 우리가 위치 투명성이라고 부르는 것이다. 공간 투명성은 때때로 '투명 분산 컴퓨팅'으로 잘못 이해되지만, 사실은 반대의 경우이다. 프로세스 내 메서드 호출을 네트워크 (ala RPC, XA 등) 상에서 모방하는 것이 아니라 네트워크와 그 제약사항 (부분 실패, 네트워크 분할, 메시지 유실, 비동기, 메시지 기반의 특성)을 전부 아우르는 프로그래밍 모델의 일급 객체로 만든다. 위치 투명성에 대한 우리의 견해는 Waldo et al의 A Note On Distributed Computing 과 정확히 일치한다.

메시지 기반 (이벤트 기반과 대조)

메시지는 특정 대상으로 보내지는 데이터 항목이다. 이벤트는 컴포넌트 가 주어진 상태에 도달했을 때 발생시키는 신호이다. 메시지 기반 시스템에서는 주소 지정이 가능한 수신자가 메시지 도착을 기다리고 메시지에 응답하며 그렇지 않을 경우 휴면한다. 이벤트 기반 시스템 알림에서 리스너는 이벤트 발생지에 소속되어 이벤트가 발생할 때 호출된다. 즉, 이벤트 기반 시스템은 주소 지정이 가능한 이벤트 발생지에 초점을 맞추고 메시지 기반 시스템은 주소 지정이 가능한 수신자에 집중한다. 메시지는 인코딩된 이벤트를 페이로드로 포함할 수 있다.

이벤트 소비 사슬의 수명이 짧으므로 이벤트 기반 시스템에서는 복원력을 얻는 것이 더 어렵다. 작업이 실행될 때 결과에 응답하기 위한 리스너들이 존재하는데 이러한 리스너들은 일반적으로 결과의 성공 또는 장애 (오류와 대조)를 직접 처리하고 본 클라이언트에게 알린다. 하지만 컴포넌트를 복원하기 위해 장애에 대응할 때는 이것을 일시적인 클라이언트의 요청에 대한 것이 아니라 컴포넌트의 전반적인 상태에 대응하는 것으로 처리해야 한다.

논 블로킹(Non-Blocking)

동시성 프로그래밍에서는 자원을 경쟁하는 스레드가 자원을 보호하는 상호 배제로 무기한 연기되지 않도록 논 블로킹 알고리즘이 고려된다. 일반적으로 이것은 API로 선언되는데, 만약 자원 이 사용 가능하다면 접근을 허용하고 그렇지 않다면 현재 자원을 사용할 수 없다는 응답이나 작업이 시작되었지만, 아직 완료되지 않았음을 호출자에게 즉시 반환한다. 자원에 대한 논 블로킹 API를 사용하면 호출자가 자원을 사용할 수 있을 때까지 기다리지 않고 다른 작업을 수행할 수 있다. 자원을 사용하려는 클라이언트를 등록하여 자원이 사용 가능해지거나 작업이 완료될 때가 알림을 받을 수 있도록 보완할 수 있다.

프로토콜

프로토콜은 컴포넌트 간의 메시지 교환이나 전송을 위한 처리 방식을 정의한다. 프로토콜은 교환하는 참가자들 사이의 관계, 누적된 프로토콜의 상태 그리고 전송하도록 허용된 메시지 집합으로 나타낼 수 있다. 즉, 프로토콜은 참가자가 특정 시점에 다른 참가자에게 보내는 메시지를 나타낸다. 프로토콜은 교환 형태에 따라 분류할 수 있는데, 일반적인 분류로는 요청-응답, (HTTP와 같은) 반복적인 요청-응답, 발행-구독, 그리고 (push와 pull을 모두 포함하는) 스트림이 있다.

프로토콜은 둘 이상의 참가자를 포함할 수 있고 메시지 전달 상태를 예측할 수 있다는 점에서 로컬 프로그래밍 인터페이스보다 더 포괄적이다. 인터페이스는 오직 호출자와 수신자 사이의 한 번에 하나의 상호 작용만 명시한다.

여기서 정의하는 프로토콜은 전송할 메시지를 지정하지만 어떻게 전송할지는 지정하지 않는다는 점에 유의해야 한다. 인코딩, 디코딩 (예: 코덱) 및 전송 방식은 컴포넌트들의 프로토콜 사용에서는 구애받지 않는 세부 구현 정보이다.

복제

서로 다른 곳에서 동시에 한 컴포넌트 를 실행하는 것을 복제라고 한다. 이것은 서로 다른 스레드 혹은 스레드 풀, 프로세스, 네트워크 노드 또는 컴퓨팅 센터에서 실행되는 것을 의미한다. 복제는 유입되는 작업 부하를 컴포넌트의 여러 인스턴스에 분산하는 확장성과 작업 부하가 복제되어 여러 인스턴스에서 같은 요청을 병렬 처리하는 복원력을 제공한다. 이러한 접근법은 혼합될 수 있다. 예를 들어, 컴포넌트의 특정한 사용자에 관련된 모든 트랜잭션은 두 개의 인스턴스에서 처리하게 하고 전체 인스턴스의 개수는 들어오는 부하에 따라 결정되도록 보장할 수 있다(탄력성 (확장성과 대조) 참조).

자원

컴포넌트 가 기능을 수행하기 위해 의존하는 모든 것을 자원이라고 하는데, 컴포넌트의 필요에 따라 제공되어야 한다. 여기에는 CPU 할당, 주 메모리 및 영구 저장소는 물론 네트워크 대역폭, 주 메모리 대역폭, CPU 캐시, 소켓 간 CPU 링크, 안정적인 타이머 및 작업 스케줄링 서비스, 기타 입출력 장치, 데이터베이스 또는 네트워크 파일 시스템과 같은 외부 서비스가 포함된다. 필요한 자원이 부족할 경우 컴포넌트가 필요한 시점에 작동하지 못하게 되므로 이러한 모든 자원에 대한 탄력성 (확장성과 대조)과 복원성을 고려해야 한다.

확장성

시스템의 기능 중 성능을 높이기 위해 더 많은 컴퓨팅 자원을 사용하는 것은 자원 증가에 대한 입력 처리량의 증가 비율로 측정한다. 완벽하게 확장 가능한 시스템은 이 두 숫자가 비례한다는 특성이 있다: 자원을 두 배 할당하면 처리량이 두 배가 된다. 시스템 내의 병목 지점 또는 동기화 지점의 도입은 일반적으로 확장성을 제한하는 원인이다. Amdahl’s Law and Gunther’s Universal Scalability Model 참조.

시스템

시스템은 사용자나 클라이언트에게 서비스들을 제공하며 조합되는 컴포넌트 의 수에 따라 커지거나 작아질 수 있다. 시스템 내의 모든 컴포넌트는 이러한 서비스들을 제공하기 위해 협력한다. 많은 경우에 컴포넌트들은 같은 시스템 내에서 클라이언트-서버 관계에 있다 (프론트엔드 컴포넌트들이 백엔드 컴포넌트들에 의존하는 경우 등). 한 시스템은 공통된 복원 모델을 공유하여 시스템 내의 컴포넌트 장애 (오류와 대조)는 다른 컴포넌트로 위임 되어 시스템 내에서 처리된다. 시스템 내 컴포넌트 묶음이 가지는 기능, 자원 혹은 장애 모델이 시스템의 나머지 부분과 분리 (그리고 억제)된다면 이것을 하위 시스템으로 보는 게 유용하다.

사용자

우리는 이 용어를 비공식적으로 어떠한 서비스를 소비하는 사람이나 다른 서비스를 의미하는 데 사용한다.

↑ 위로 돌아가기