01.Rxjava와 리액티브 프로그래밍

1. What is RxJava?

자바(Java)에서 리액티브 프로그래밍(Reactive Programming)을 구현하는데 사용하는 라이브러리입니다.

이벤트 처리와 같은 비동기 처리에 최적화됐으며, 2.0버전부터 Reactive Streams 사양을 구현합니다. Reactive Streams 사양을 구현합니다. Reactive Streams는 어떤 라이브러리나 프레임워크라도 데이터 스트림을 비동기로 처리하는 공통 메커니즘을 인터페이스로 제공합니다.

즉, RxJava2.0부터는 Reative Streams API를 의존하고 Reactive Streams를 제외한 다른 라이브러리는 의존하지 않습니다. RxJava는 함수형 리액티브(Functional Reactive Programming)은 아니지만, 함수형 프로그램의 영향을 받아 함수형 인터페이스를 인자로 전달받는 메서드가 많습니다. 이러한 함수형 인터페이스를 사용하는 메서드들을 조합하면 함수형 프로그래밍을 하는 것 처럼 데이터를 필터링하거나 변환하는 등의 처리를 유연하게 할 수 있습니다.

1.1. Rxjava의 지원 버전

Java 6 버전 이상과 안드로이드2.3버전 진저브레드(gingerbread)이상을 지원합니다.

1.2. RxJava 기본 출력해보기

1
2
3
4
5
6
7
8
import io.reactivex.Flowable;

public class RxjavaOutput {
public static void main(String[] args) {
Flowable<String> flowable = Flowable.just("Hello", "World");
flowable.subscribe(data-> System.out.println(data));
}
}

1.3. 처리 순서

  • just 메서드 인자로 전달된 데이터를 통지하는 생산자(Flowable)를 생성합니다.
  • 생산자가 데이터를 통지하면 소비자(람다식으로 구현된 함수형 인터페이스) 데이터 출력이 됩니다.

2. What is reactive programming?

데이터가 통지될 때마다 관련 프로그램이 반응(reaction)해 데이터를 처리하는 프로그래밍 방식입니다.

2.1. Example of reactive programming

GPS위치 정보가 변경될 때의 데이터 전송 흐름을 상상해보면 이해하기 쉽습니다. 이동해 위치 정보가 변경될 때마다 데이터를 전송하고 이동을 멈추면 데이터전송을 중지하는 것처럼 생성되는 데이터를 한 번에 보내지 않고 각각의 데이터가 생성될 때마다 순서대로 보냅니다. 이러한 데이터의 흐름을 데이터 스트림(data stream) 이라고 합니다.

이미 생성된 데이터 집합인 리스트(list)같은 컬렉션(collection) 과는 다르게 앞으로 발생할 가능성이 있는 데이터 까지도 포함하는 데이터 집합체 입니다.

데이터 스트림은 이벤트와도 관련이 있어서 문자열을 입력하는 행위는 입력한 데이터가 순서대로 생성하는것으로 생각 할 수 있습니다.

예를 들어, "abc"라고 입력하면 입력 이벤트가 발생할때 다음과 같은 데이터가 생성된다고 생각할 수 있습니다.

1
2
3
1. [a]
2. [ab]
3. [abc]

마찬가지로 버튼을 누르는 행위에 대한 구체적인 데이터가 없더라도 버튼 이벤트와 같은 데이터가 생성된다고 생각할 수 있습니다. 버튼을 여러번 누른다면 누른 횟수만큼 버튼을 누른다 라는 이벤트가 발생할 수 있습니다.

즉, 이벤트도 발생할 때마다 데이터를 전송하는 데이터 스트림으로 다룰 수 있습니다. 데이터 스트림으로 데이터를 전달받은 프로그램이 그때마다 적절히 처리 할 수 있게 구성됐습니다.

⇒ 결론적으로 필요한 데이터를 직접 가져와 처리하는것이 아니라 보내온 데이터받은 시점에 반응해 이를 처리하는 프로그램을 만드는것이 리액티브 프로그래밍입니다.

또 다른 예로, 상품가격과 부가가치세 세율로 부가가치세를 계산하는 프로그램이 있다고 할때, 리액티브 프로그래밍이 아니라면 상품가격과 부가가치세 세율을 얻는 것만으로는 어떤 일도 일어나지 않습니다.

값을 얻은 후에 부가가치세를 계산한다 라는 행위(action)이 이루어져야 비로소 부가 가치세를 계산합니다. 또한, 부가 가치세를 계산한 후 상품가격이 변경되더라도 다시 계산처리 행위가 이루어지지 않는 한 부가가치세는 변경되지 않습니다.

2.2. 리액티브 프로그래밍이 아닐때

  1. 입력한다
  2. 버튼이 눌린다
  3. 계산 결과를 표시한다

상품 가격이 바뀌어도 세금계산 버튼을 누르지 않으면 부가가치세가 바뀌지 않는다.

2.3. 리액티브 프로그래밍일 때

  1. 입력한다
  2. 입력한 내용을 통지한다
  3. 통지를 받아 계산하고 결과를 표시한다

상품가격이 바뀔 때마다 부가가치세가 자동으로 계산된다.


상품 가격 변동을 감지하는 리스너(listener)를 이용해 자동으로 부가가치세를 계산하는 프로그램과 어떤 차이가 있는지 의문이 생길 수 있습니다.

예를 들어, 상품가격이 변경 될때 반응하면서 상품가격에 해당하는 부가가치세를 다시 계산해 표시하는 것을 리액티브 프로그래밍이라 할 수 없습니다.

리스너(listener)가 반응하면서 부가가치세 항목에 새로운 데이터가 전달되고 부가가치세 항목에서 계산 프로그램을 실행해 결과를 부가가치세로 표시한다고 생각하면 리액티브 프로그래밍이라고 할 수 있습니다.

⇒ 리액티브 프로그래밍에서 데이터를 생산하는 측이 데이터를 전달하는것까지 책임집니다. 데이터를 생산하는측(상품가격)은 데이터를 전달하는것까지 책임집니다. 그러므로 데이터를 생산하는 측은 데이터를 소비하는 측(예 부가가치세)이 전달 받은 데이터로 무엇을 하는지 관여하지 않아도 됩니다.

데이터를 생산하는 측은 데이터를 소비하는 측에 무엇을 하든지 관계가 없으므로 소비하는 측의 처리를 기다릴 필요가 없습니다. 그러므로 데이터를 통지한 후 데이터를 소비하는 측에서 데이터를 처리하는 도중이라도 데이터를 생산하는 측은 바로 다음 데이터를 처리 할 수 있습니다.

2.4. 시스템 구축의 관점

리액티브 프로그래밍은 마이크로서비스(Miscroservice)와 같이 분산 시스템으로 프로그램을 구현하는데 적합해 최근 주목을 받고 있습니다.

리액티브 프로그래밍(Programming)리액티브 시스템(System)으로 부르지 않고 리액티브 시스템이 리액티브 프로그래밍으로 구현된 시스템을 의미하지 않기 때문입니다.

2.5. 리액티브 시스템이란?

메시지를 보내 데이터를 처리하고 상황에 따라 스케일 아웃(scale out)과 스케일 인(scale in)을 자동으로 수행해 장애 내성을 높임으로써 항상 빠르게 수용할 수 있는 시스템을 말합니다.(인프라 조건+)

3. RxJava의 개요

에릭마이어가 개발한 .net 프레임워크의 실험적인 라이브러리인 Reactive Extensions 를 줄여서 2009년 마이크로소프트에서 공개하고 2013년 넷플릭스가 자바로 이식한 것이 Rxjava의 시작입니다.

현재 Reative Extensions를 다루는 라이브러리는 ReactiveX 라는 오픈소스 프로젝트로 바뀌어 Java, .Net, javascript, Swift 등 여러 프로그래밍 언어를 지원하고 있습니다.

RxJava 1.x버전 때는 자바에 Reactive Extensions를 이식하는 개발이 진행됐고, 리액티브 프로그래밍 개념이 널리 알려지면서 Reactive Extensions와 별도로 여러 업체와 단체에서 데이터 스트림을 비동기로 다루는 라이브러리와 프레임워크를 출시하였습니다.

라이브러리, 프레임워크 차이로 단체들이 데이터 스트림을 비동기로 다루는 최소한의 API를 정하고 제공했습니다. 2015년 4월 자바기반의 Reactive Streams for JVM 버전이 1.0.0을 릴리즈하게 되었습니다.

Rxjava 1.x버전때는 Reative Streams를 지원하지 않았지만, Rxjava 2.x버전때는 Reative Streams를 지원하여 2016년 10월에 Rxjava2.0이 릴리즈 되었습니다. Rxjava2.0버전부터 내부를 완전히 새롭게 구현하여 성능개선과 배압(back pressure) 사양에 따라 사용하는 API가 변경됐습니다.

그리고, Rxjava 1.x버전에서 2.x버전으로 전환할 때는 API 변경 작업도 반영해야 하므로 2.x버전으로 간단하게 전환할 수가 없습니다. 그 이유는 내부구현을 모두 바꾸었기 때문입니다.

  • 버전별 루트 패키지
버전 패키지
1.x rx
2.x io.reactivex

따라서, RxJava의 두 버전을 같은 프로젝트에 함께 사용할 수는 있으나 프로젝트 내부에서 Rxjav에 의존하는 다른 라이브러리를 사용한다면 라이브러리가 어떤 버전을 지원하느냐에 따라 두 버전을 함께 사용하지 못할 수도 있습니다.

  • 두 버전을 사용하는것은 바람직 하지 않습니다.

Rxjava의 실험적인 API가 있습니다. 해당 에너테이션이 붙어 있는것은 개발중이거나 실험중인 API입니다.

  • @Beta @Experimental

추가로 io.reactivex.internal로 시작하는 패키지에 있는 클래스는 Rxjava 내부에서 기본으로 사용하는 클래스입니다. 가능하면 클래스에 의존하지 않는 편이 더 낫습니다.

4. RxJava의 특징

Rxjava는 디자인 패턴인 옵저버(Observer)패턴을 잘 확장했습니다.

4.1. 옵저버패턴이란?

감시 대상 객체의 상태가 변하면 이를 관찰하는 객체에 알려주는 구조입니다. 이 패턴의 특징을 살리면 데이터를 생성하는 측과 데이터를 소비하는 측으로 나눌 수 있습니다.

또한, 옵저버패턴에 완료와 에러통지를 할 수 있어서 모든 데이터 통지가 끝나거나 에러가 발생하는 시점에 별도로 대응해줄수도 있습니다.

4.2. 비동기 처리

Rxjava의 또 다른 특징으로 쉬운 비동기 처리를 들 수 있습니다. Reactive Streams 규칙의 근간이 되는 Observable규약 이라는 Rxjava개발 가이드라인을 따른 구현이라면 직접 스레드(thread)를 관리하는 번거로움에서 해방되고 구현도 쉽게 가능합니다. 또한, 동기 처리나 비동기 처리나 구현 방법에는 큰 차이가 없는 것도 Rxjava의 특징입니다.

RxJava는 함수형 프로그래밍의 영향을 받아 함수형 인터페이스로 인자를 전달받는 메서드를 사용해 대부분의 처리를 구현합니다. 입력과 결과만 정해져 있으면 구체적인 처리는 개발자에게 맡길 수 잇으므로 더욱 자유로운 구현이 가능합니다.

4.3. 함수형 프로그램의 원칙

  • 처리 작업의 영향 범위를 좁힐 수 있고 동시에 복잡하지않게 비동기 처리를 할 수 있습니다.