Spring mvc는 분명 "multi Thread, sync, Blcoking" 방식을 통해 Node.js 대비 이점이 존재하지만, 단점 역시 존재한다.
그리고 이러한 단점이 요즘의 애플리케이션 개발 트렌드에 적합하지 않기에 Spring webflux등의 Reactive Stack을 통한 리액티브 프로그래밍을 통해 이러한 단점을 극복하도록 지원한다.
하지만, Spring의 Reactive Stack와 유사하게, express 기반의 Node.js 역시 async, non-blocking, event-driven 방식을 사용한다.
이번 글에선 스프링 webflux와 유사하게 async, non-blocking, event-driven 방식을 사용하는 Node.js를 비교분석해보겠다.
1) Spring webflux는 리액티브 패러다임을 기반으로 만들어졌다.
둘을 서로 다른 동시성 모델을 가지고있다.
Express
Express는 단일 스레드의 이벤트 루프 기반 모델을 사용하여 비동기 및 이벤트 기반 처리를 한다. 이는 Node.js의 기본 동작 방식이다. Express는 콜백(Callback)이나 프로미스(Promise)와 같은 비동기 패턴을 사용하여 요청을 처리하고, 이벤트 루프를 통해 비차단(non-blocking) 방식으로 작업을 처리한다.
이벤트 루프
이벤트 루프는 단일 스레드에서 이벤트 처리와 작업을 관리한다. 기본적으로 이벤트가 발생하면 해당 이벤트는 이벤트 큐에 추가되고, 이벤트 루프는 이벤트 큐(Event Queue)에 등록된 이벤트와 작업을 순차적으로 처리한다. 이때, 이벤트의 처리는 비동기로 이루어지므로 다른 작업이 블로킹되지 않고 계속해서 처리할 수 있다.
단점
- 개발자가 작성한 코드에 대한 직접적인 제어를 가지고 있기에, 개발자는 결과에만 집중할 수 없다.
CallBack
CallBack함수를 자신이 호출하는 함수의 파라미터(인자)로 넘겨주고 자신은 더이상 관여하지 않는 것으로 Aync&non-blocking을 성취한다.
단점
- 콜백 지옥(callback hell)과 같은 문제가 발생할 수 있다.
- 비동기 코드의 작성과 관리가 어려울 수 있다.
콜백 지옥
비동기 작업을 처리하기 위해 콜백 함수를 중첩해서 사용할 때 발생하는 코드의 가독성과 유지보수성이 저하되는 문제
Node.js는 비동기 I/O를 처리하기 위해 콜백 함수를 자주 사용한다.
예를 들어, 파일 읽기, 네트워크 요청 등의 작업은 비동기적으로 처리되며, 작업이 완료되면 콜백 함수가 호출된다.
이러한 방식은 동시성을 유지하면서 다수의 작업을 처리할 수 있어 효율적이다.
그러나 콜백 함수를 중첩해서 사용하다 보면 코드가 길어지고 가독성이 떨어지며, 에러 처리와 제어 흐름 관리가 복잡해진다.
WebFlux
WebFlux는 Reactor라는 리액티브 스트림 라이브러리를 기반으로 한 리액티브 프로그래밍 모델을 사용한다. 이는 비동기 및 이벤트 기반 프로그래밍을 강조하며, 데이터 스트림을 처리하고 변환하는데 강력한 도구를 제공한다.
Reactor 기반 리액티브 프로그래밍
이벤트는, 데이터의 변화를 나타낸다. 그리고 Pub-Sub라는 통신 방식을 통해 Subscriber들이 자신이 변화를 감지하고 싶은 Publisher들을 구독하면, Publisher가 자신의 변화를 Observer패턴을 통해 자신을 구독하는 Subscriber에게 자신이 변화했다는 Event를 전달해준다.
그리고 UI와 서버는 유저의 눈에 보이지 않게 계속해서 통신을 수행하며, 그때마다 Observer 패턴으로 감지한 변화를 반영하는 것으로 "실시간 반영"을 얻는다고 보면된다.
이 둘은 어떤 차이가 있을까?
콜백&이벤트 루프 vs 리액티브 타입
Express에서는 비동기 작업을 처리하기 위해 콜백 패턴& 이벤트 루프을 사용하고, WebFlux에서는 리액티브 타입(Flux와 Mono)을 사용하여 데이터 스트림을 다룬다.
이벤트 루프 동작
Express에서는 비동기 작업을 처리하기 위해 콜백 패턴& 단일 스레드의 이벤트 루프를 사용하여 비차단(non-blocking) 방식으로 작업을 처리한다.
장점
- 메모리 사용량이 적고, 동기화 문제가 적어서 확장성이 좋다.
- 비동기 작업을 효율적으로 처리할 수 있고, 대규모 연결을 처리하는데 적합하다.
단점
- CPU 집중적인 작업이나 오래 걸리는 작업을 처리할 때 전체 시스템의 응답성이 저하될 수 있다.
- 단일 스레드로 동작하므로 여러 작업이 동시에 실행되지 않고 순차적으로 처리되기 때문에 병렬 처리에 제한이 있을 수 있다.
리액티브 타입
WebFlux는 Reactor의 스케줄러를 통해 비동기 작업을 관리하며, 스레드 풀을 활용하여 동시성을 제어한다.
장점
- 리액티브 프로그래밍 모델을 사용하여 비동기 작업을 선언적으로 다룰 수 있습니다.
- 데이터 스트림을 조작하고 변환하기 위한 다양한 연산자를 제공합니다.
- 동시성을 높일 수 있고, 대용량 및 고부하 환경에서 더 높은 성능을 제공할 수 있습니다.
단점
- 추가적인 러닝 커브가 있을 수 있으며, 리액티브 연산자를 사용하는 방법에 대한 이해가 필요하다.
- 기존의 콜백 패턴이나 프로미스와 같은 비동기 패턴을 사용하는 코드와의 호환성을 고려해야 한다.
- 스레드 풀을 사용하므로 메모리 사용량이 증가할 수 있다.
절차적 vs 선언적
- Express의 콜백 패턴은 절차적인 방식으로 비동기 작업을 다룬다.
- WebFlux의 리액티브 프로그래밍 모델은 선언적인 방식으로 비동기 작업을 다루고 데이터 스트림을 조작한다.
-> webflux는 Reactive 패러다임을 통해 실행의 제어 흐름을 더욱 추상화하고, 개발자는 결과에 집중할 수 있다.
절차적 방식 (Procedural Approach):
- 절차적 방식은 코드의 실행 순서에 집중합니다.
- 코드는 명령문의 연속으로 구성되며, 작업을 수행하기 위해 순차적으로 실행됩니다.
- 프로그램의 흐름이 명시적으로 제어되며, 상태(state)를 변경하고 다음 동작을 수행하는 방식입니다.
- 비동기 작업을 처리하기 위해 콜백 패턴이나 프로미스를 사용하여 비동기 코드의 흐름을 관리하는 경우가 있습니다.
- 개발자가 작성한 코드에 대한 직접적인 제어를 가지고 있습니다.
선언적 방식 (Declarative Approach):
- 선언적 방식은 코드가 무엇을 하는지에 집중합니다.
- 코드는 선언적 문장이나 표현식으로 구성되며, 프로그램이 무엇을 달성해야 하는지를 명시합니다.
- 상태 변경보다는 원하는 결과에 초점을 맞추며, 원하는 결과를 얻기 위해 필요한 작업을 추상화하여 표현합니다.
- 리액티브 프로그래밍에서는 Flux와 Mono와 같은 리액티브 타입을 사용하여 비동기 작업을 선언적으로 표현하고 데이터 스트림을 조작합니다.
- 실행의 제어 흐름을 더욱 추상화하고, 개발자는 결과에 집중할 수 있습니다.
요약
- WebFlux는 보다 선언적이고 유연한 비동기 작업 처리를 제공하며, 데이터 스트림을 조작하기 위한 다양한 연산자를 활용할 수 있다.
- Express는 간단하고 경량한 웹 프레임워크로서 비동기 작업을 콜백 패턴을 통해 처리하고, 이벤트 루프를 통해 비차단 방식으로 동작한다.
why Reactive?
아래의 글에 리액티브 프로그래밍의 자세한 내용, 그리고 왜 Reactive Programming이 강점을 가지는지 정리해놨으니 참고하자.
https://codenme.tistory.com/124
성능 테스트
아래는, 서칭중에 찾은 Node.js 기반 Express와 webflux의 성능 비교 글이다. 아래의 테스트를 통해 Reactive의 성능적 이점을 어느정도 체감하는데 도움이 될 것이다.
여기까지만 보면, Reactive 프로그래밍이라는 거대한 강점이 Spring webflux만의 전유물인 것 같지만, Spring에 webflux가 존재하듯이, Node.js기반의 express 프레임워크도 RSJS를 통해 리액티브 프로그래밍이 가능하고, async/await을 통해 콜백 지옥 문제도 해결할 수 있다.
RxJS란?
RxJS는 ReactiveX 프로그래밍을 JavaScript로 구현하기 위한 라이브러리입니다. 이 라이브러리는 옵저버블(observable)과 옵저버(observer)를 사용하여 데이터 스트림을 처리하고 변환하는 강력한 도구를 제공합니다. RxJS는 비동기 데이터 스트림을 다루기 위한 연산자들을 제공하며, 데이터 스트림에 대한 변화를 모니터링하고 이를 처리하는 방식을 선언적으로 표현할 수 있습니다.
그렇기에 이러한 차이점은 머리속에 담아 두기만 하자.
그럼 근본적으로, 둘 사이엔 어떤 차이가 있을까?
2) 언어, 플랫폼, 프레임워크의 차이점
당연하게도 둘은 사용하는 언어, 플랫폼, 프레임워크가 다르고 여기서 오는 차이점이 존재한다.
언어 및 프레임워크
- WebFlux는 Java 기반의 Spring Framework의 일부로서 Java 언어를 사용한다.
- Express는 Node.js 기반의 웹 프레임워크로서 JavaScript 언어를 사용한다.
플랫폼
- WebFlux는 Java Virtual Machine (JVM) 위에서 동작하며, Java 생태계와의 통합을 강조합니다.
- Express는 Node.js 플랫폼 위에서 동작하며, JavaScript 생태계와의 통합을 강조한다.
생태계와 커뮤니티
- Java와 Spring Framework는 긴 역사와 다양한 라이브러리 및 도구를 갖춘 대규모 생태계를 가지고 있다.
- Node.js와 Express는 JavaScript 생태계에서 활발하게 발전하고 있으며, 다양한 모듈과 패키지, 개발자 커뮤니티가 있다.
Why Spring WebFlux?
필자는 Spring에 관심을 가졌었다. 그 이유는 결국 위와 같은 Spring의 국내 시장에서의 점유율이 가장 큰 이유였다.
Java는 오랫동안 인기를 유지했던 언어이고, 특히 국내에선 여전히 강세를 띄고 있다. 그렇기에 계속해서 사용되고, 레퍼런스가 많은 Java, 그리고 그를 편리하게 해주는 ioc, DI 와 같은 패러다임을 제공하는 Spring 프레임워크를 기반으로 Reactive 패러다임을 사용할 수 있다는 건, 엄청난 메리트이다.
하지만, 해외의 경우 java 강점기가 종식되었기에, 자신의 진로, 환경, 성향에 따라 적절하게 선택하는 것이 필요하다.
+@
아래는, 우아한 tech 세미나에서 Node.js와 webflux를 통한 스프링 리액티브의 비교 질문이 나와서, 그에 대해 정리한 글이다. 이것도 참고하자!
Q. NodeJS (Promise / Async / Await)가 있는데 굳이 스프링 리액티브를 써야하는지?
- 질문대로 Spring을 Node처럼 쓰고자 등장
- 이미 검증된 버츄얼머신 (JVM) 을 쓰고, 방대한 생태계를 그래도 사용하면서 비동기/논블로킹 프로그래밍을 하고자 하는 의도
- 사실 비동기 서블릿이 나온건 2009년
- 실제로 Node보다는 빨리 등장
- 단, 사람들이 관심이 없었음
- 비슷하게 스프링부트 역시 RoR (루비온레일즈)처럼 쓰고자 등장
- Node를 제외하면 사실 대부분의 프로그래밍에서는 UI 시스템에서 비동기/논블로킹을 사용
- 서버사이드에서 이를 해결하기 위해 RxJava를 많이 사용하게 됨
- 실제로 Java -> Node로 전환했다는 이야기보다는 Node -> Java로 전환했다는 이야기가 훨씬 많음
'MSA, EDA, Reactive 패러다임' 카테고리의 다른 글
EDM 아키텍처를 통한 통합 거래 및 이상 거래 탐지 시스템 구축(PT 발표 자료 및 스크립트) (0) | 2023.09.11 |
---|---|
(EDM) Event Driven MicroService 기초 지식 정리 (0) | 2023.07.07 |
Reactive System과 event-driven Architecture (0) | 2023.07.06 |
Request-Respone(Rest 통신) VS 비동기 메세지 통신(Pub-Sub) (0) | 2023.07.06 |
reactive programing [이론 정리] (0) | 2023.07.06 |