728x90
반응형
Reactive Programing 의 등장
현재 소프트웨어의 아키텍처는 아래의 상황을 대응해야 한다.
리액티브는 비동기 기반으로 데이터를 처리하여 아래 상황들을 어플리케이션 관점에서 해결해준다..
- 빅데이터 처리
- 다양한 환경:하나의 모바일 디바이스에서 다양한 환경에 애플리케이션이 배포된다.
- 사용패턴: 사용자는 1년 내내 항상 서비스를 이용할수 있으면 밀리초단위의 응답시간을 기대한다
- 여기서 중요한 단어는 빅데이터 처리, 다양한 환경, 밀리초의 응답이라고 생각한다.
이를 수용하기 위해 리액티브 프로그래밍이 등장 하였다.
Blocking 방식의 문제점
- 코드를 블록킹 방식으로 작성하면 일반적으로는 문제가 없지만
버틀넥(병목)이 발생하면 문제가 크다. - 그때 Thread 를 추가하거나 서버 또는 자원을 추가해서 해결하는 방법이 있지만
동시성 문제가 발생하고 어플리케이션에 심각한문제가 생길수 있다.
Blocking 코드에서 성능을 개선하는 방법 3가지
- parallelize(병렬처리)
- callback 처리
- completableFuture
parallelize 의 문제점
- 블록킹 방싱의 코드는 시간이 오래걸릴수 있는 데이터 베이스 요청이나, 다른 API 통신을 할때
완료 될때까지 쓰레드가 유휴로 남아 대기상태로 있어 자원을 낭비한다. - 그렇기 때문에 병렬화로 모든것을 해결 할수 없다. 또한 여러 서버에서 동일한 로직들이 발생하기 때문에
디버깅이 쉽지 않을수 있다.
Callback 의 문제점
- 콜백은 여러개의 콜백을 합쳐서 개발하기 힘들다.
- 콜백 지옥에 빠질수 있다.
CompletableFuture 의 한계
- 복잡한 코드방식
Callback Vs Reactor
- 동일한 코드를 콜백으로 작성했을때와 리액터로 작성했을때 차이를 보자
- CompletableFuture 도 비슷하여 생략한다.
Callback
userService.getFavorites(userId, new Callback<List<String>>() {
public void onSuccess(List<String> list) {
if (list.isEmpty()) {
suggestionService.getSuggestions(new Callback<List<Favorite>>() {
public void onSuccess(List<Favorite> list) {
UiUtils.submitOnUiThread(() -> {
list.stream()
.limit(5)
.forEach(uiList::show);
});
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
});
} else {
list.stream()
.limit(5)
.forEach(favId -> favoriteService.getDetails(favId,
new Callback<Favorite>() {
public void onSuccess(Favorite details) {
UiUtils.submitOnUiThread(() -> uiList.show(details));
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
}
));
}
}
public void onError(Throwable error) {
UiUtils.errorPopup(error);
}
});
Reactor
- 코드가 훨씬 깔끔하다.
- 추가로 timeout 과 Error 처리를 쉽게 할수 있다.
userService.getFavorites(userId)
.timeout(Duration.ofMillis(800))
.onErrorResume(cacheService.cachedFavoritesFor(userId))
.flatMap(favoriteService::getDetails)
.switchIfEmpty(suggestionService.getSuggestions())
.take(5)
.publishOn(UiUtils.uiThreadScheduler())
.subscribe(uiList::show, UiUtils::errorPopup);
Reactive Programing
리액티브 프로그래밍에서는 다양한 시스템과 소스에서 들어오는 데이터 항목스트림을 비동기적으로 처리한다.
비동기적으로 처리된 데이터 항목들을 합친다.
특징
반응성:
- 빠르다.
- 일정하고 예상할 수 있는 반응 시간을 제공한다.
- 결과적으로 사용자가 기대치를 가질 수 있다.
- 기대치를 통해 신뢰가 증가하면 신뢰할수 있는 애플리케이션이 된다.
회복성:
- 장애가 발생해도 시스템은 반응 해야 한다.
탄력성:
- 애플리케이션의 생명주기 동안 다양한 작업 부하를 받게 된다.
- 리액티브는 자동으로관련 컴포넌트의 할당된 자원 수를 늘린다.
메시지 주도:
- 비동기 메시지를 통해 통신이 이루어진다.
Reactive 의 수준
- Recative의 수준에는 2가지가 있다.
- 애플리케이션
- 시스템
애플리케이션 수준의 리액티브
- 스레드를 퓨처, 액터, 일련의 콜백을 발생시키는 이벤트 루프등과 공유하고 처리할 이벤트를 변환하고 관리한다.
- 사용되는 기술들은 아래와 같다.
- 이벤트, 메시지, 시그널, 이벤트 루프등을 이용하여 비동기 작업을 할수 있다.
- 스레드 보다 가볍다.
- 동기블록, 경쟁조건, 데드락 같은 저수준의 멀티스레드 문제를 직접 처리할 필요가 없어진다.
시스템 수준의 리액티브
- 애플리케이션들중에 하나가 실패해도 전체시스템은 계속해서 운영하게 해주는 소프트웨어 아키텍처이다.
- 애플리케이션을 조립하고 상호소통을 조절한다.
- 사용되는 방식
- 가장 주요한 속성중 하나는 메시지 주도 방식이다.
- MSA 방식도 그중 하나다
- 각각의 애플리케이션들이 독립적으로 동작하기 때문에 결합력이 낮아진다.
- 문제가 발생하더라고 장애를 고립시켜 다른 애플리케이션들에게 영향을 주지 않는다.
Reactive stream 의 동작 방식
Publisher:
- 데이터를 방출(게시)하는 역할을 한다.
- 데이터를 방출하지만 subscirber가 없으면 데이터는 처리 되지 않는다.
Subscriber:
- Publisher에서 방출된 데이터를 가져오는(구독) 역할을 한다.
- 여기서 데이터를 처리한다.
Backpressures:
- 역압력이라고 한다. 받을수 있는데이터의량 처리가 되었는지 등등 pub에게 알려주는 역할을 한다.
- 이때 pub 에서 게시하는 속도가 빠르고 sub 에서 처리하는 속도가 느리면 데이터가 쌓일것이다.
- 그럴때 sub 은 역압력을 이용하여 pub 에게 처리가능한 데이터의 량을 알려줄수 있다.
- 그역할을 하는것이 역압력이다.
728x90
반응형
'Reactive Programing' 카테고리의 다른 글
[Reactive Programming] zipWith (0) | 2024.11.09 |
---|---|
[Reactive Programming] 속도비교 (1) | 2024.11.02 |
[Reactive Programming] Flux, Mono 개념 (0) | 2024.10.14 |
댓글