Spring/Webflux

리액티브 프로그래밍이란

개발정리 2024. 1. 27. 21:08
  • 리액티브 프로그래밍이란 데이터 또는 이벤트의 변경이 발생하면 이에 반응해 처리하는 프로그래밍 기법을 말한다.
  • 리액티브 프로그래밍은 비동기 프로그래밍을 처리하는 새로운 접근 방식.
  • 리액티브 프로그래밍은 데이터의 통지, 완료, 에러에 대한 처리를 옵저버 패턴에 영감 받아 설계되었고, 데이터의 손쉬운 비동기 처리를 위해 함수형 언어의 접근 방식을 사용.
  • 리액티브 프로그래밍이 나오기 전 비동기 프로그래밍은 대부분 콜백 기반의 비동기 처리 방식을 사용했다.
fetch("/api/users/me") { user ->
	fetch("/api/users/${user.id}/followers") { followers ->
    	fetch("/api/users/${user.id}/likes") { likes ->
			fetch("/api/users/${user.id}/contacts") { contacts ->
            	// 콜백 헬
            }
        }
    }
}
  • 간단한 콜백은 이해하기 쉬울 수 있지만 콜백이 많아져서 발생하는 콜백로 인해 코드의 복잡도가 늘어난다.
  • 콜백 헬이 발생할때 어떠한 함수 내부에 있는지, 컨텍스트에 대한 흐름을 알기 어려워 안티 패턴으로도 불리고 있다.

 

리액티브 프로그래밍을 사용하면 콜백 헬 문제를 함수형 프로그래밍 관점으로 해결할 수 있다.

fetchReactive("/api/users/me")
	.zip { user -> fetchReactive("/api/users/${user.id}/followers") }
    .zip { user -> fetchReactive("/api/users/${user.id}/likes") }
    .zip { user -> fetchReactive("/api/users/${user.id}/contacts") }
    .flatMap{ followers, likes, contacts -> 
    	// 로직 구현
    }

 

  • 콜백 헬 없이 비동기 코드를 쉽게 작성할 수 있기 때문에 서버나 UI 애플리케이션 개발시 리액티브 프로그래밍이 유용하게 사용되고 있다.
  • 유저 정보를 먼저 가져오고 이와 동시에 zip 함수를 사용해서 병렬적으로 API 들을 동시에 불러왔고, 이 안에서 flatmap 을 사용하여 데이터를 조합하거나 로직을 구현하는 동작을 할 수 있다. 

 

 

리액티브 스트림

  • 리액티브 스트림은 리액티브 프로그램의 표준 API 사용을 말한다.
  • 비동기 데이터 스트림과 논-블로킹 백프레셔에 대한 사양을 제공한다.
  • 리액티브 스트림 이전의 비동기식 애플리케이션에서는 CPU의 멀티 코어를 제대로 활용하기 위해 복잡한 병렬 처리 코드가 필요했다.
  • 기존 방식은 처리할 데이터가 무한정 많아져서 시스템의 한계를 넘어서는 경우 애플리케이션은 병목 현상이 발생하거나 심각한 경우 애플리케이션이 정지되는 경우도 발생할 수 있다.
  • Netflix, Vmware, Red Hat, Twitter, Lightbend 등과 같은 유명 회사들이 표준화에 참여중이다.

 

리액티브 스트림의 구현체들 

  • TCK (Technology Compatibility Kit) 를 지원하기 때문에 라이브러리가 정해진 사양에 맞게 구현되었는지 보장할 수 있다.
    • TCK 는 라이브러리가 정해진 사양에 맞게 구현되었는지 보장하기 위해 만들어진 테스트 도구이다. 
    • 자바 진영에선 Java SE 표준을 따른 JDK 인지 검증하기 위해 TCK 를 사용한다.
  • 리액티브 스트림은 TCK만 통과한다면 각 구현체들은 표준 사양에 포함되지 않은 라이브러리만의 추가 기능도 자유롭게 지원할 수 있게 한다.
  • Reactor, RxJava, JDK9 Flow, Akka Streams, Vert.x 등이 있다. 
    • 각 구현체들마다 기본적인 리액티브 스트림 사양은 동일하게 구현하고 있지만 본인들만의 어떠한 라이브러리의 특수한 기능들이라든지 추가적인 어떤 기능들을 제공하고 있다.

 

 

  • Publisher
    • 데이터를 생성하고 구독자에게 통지
  • Subscriber
    • 데이터를 구독하고 통지 받은 데이터를 처리
      • onSubscribe - 구독시 최초에 한번만 호출
      • onNext - 구독자가 요구하는 데이터의 수 만큼 호출
      • onError - 에러 또는 더이상 처리할 수 없는 경우
      • onComplete - 모든 처리가 정상적으로 완료된 경우 
  • Subscription
    • Publisher, Subscriber 간의 데이터를 교환하도록 연결하는 역할을 하며 전달받을 데이터의 개수를 설정하거나 구독을 해지할 수 있다.
  • Processor
    • Publisher, Subscriber 을 모두 상속받은 인터페이스

 

  • 발행자는 데이터를 생성하고 구독자에게 데이터를 통지하고 구독자는 자신이 처리할 수 있는 만큼의 데이터를 요청하고 처리한다.
  • 이때 발행자가 제공할 수 있는 데이터의 양은 무한하고 순차적 처리를 보장한다.
  • 서브스크립션은 발행자와 구독자를 연결하는 매개체이며 구독자가 데이터를 요청하거나 구독을 해지하는 등 데이터 조절에 관련된 역할을 담당한다.
  • 프로세서는 발행자와 구독자의 기능을 모두 포함하는 인터페이스이며 데이터를 가공하는 중간단계에서 사용한다.