Node.js
2009년에 처음 소개된 오픈소스 Javascript 엔진인 크롬 V8에 비동기 이벤트 처리 라이브러리 libuv를 결합한 플랫폼입니다. 즉, Node.js는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임입니다.
Node.js는 공식홈페이지에서 설치할 수 있으며, 리눅스에서는 패키지 매니저를 통해서 설치를 할 수도 있습니다.
Node.js 특징
주요 특징은 아래와 같습니다.
- Chrome V8 JavaScript 엔진 기반
- 단일 쓰레드(Single Thread)와 이벤트 기반
- 비동기 I/O 처리 (Non-Blocking I/O)
- 고성능 네트워크 서버
- 개발 생산성 향상
- 방대한 모듈 제공 (NPM)
위의 특징들을 자세히 설명하겠습니다.
1. Chrome V8 JavaScript 엔진 기반 JavaScript 런타임
- 빠른 코드실행 제공
- V8 엔진을 인터프리터로 사용합니다. 따라서 빠른 실행이 가능합니다
- JavaScript 프레임워크 아닌 런타임 환경
- 런타임 환경 (runtime environment)
컴퓨터가 실행되는 동안 프로세스나 프로그램을 위한 소프트웨어 서비스를 제공하는 가상 머신의 상태
- 프레임워크 (Framework)
어플리케이션 개발에 바탕이 되는 것들의 집합
- 인터프리터 (Interpreter)
고급언어로 작성된 원시코드 명령어들을 한 번에 한 줄씩 읽어들여서 실행하는 방식
2. 단일 스레드 (Single Thread)
- 하나의 스레드가 모든 작업을 수행합니다.
- 스레드가 1개이기 때문에 메모리 사용량과 시스템 리소스 사용량 변화가 많지 않습니다.
- 따라서 대규모 네트워크 프로그램을 개발하기 적합합니다.
- 하지만 쓰레드 하나가 무너진다면 프로그램 전체에 문제가 발생합니다.
- 멀티스레드의 경우 Context Switching을 이용하여 여러 작업을 동시에 처리하는 것과 같이 느끼게 하지만, 오히려 Context Switching을 하는 시간 때문에 총 작업시간이 더 걸릴 수 있습니다.
- CPU 사용률이 높은 어플리케이션에서는 Node.js 사용 권장 X
3. 이벤트 기반 비동기 방식
쓰레드 기반 동기 방식 (Blocking I/O)
- 하나의 쓰레드가 request를 받으면 모든 처리가 완료될 때 까지 기다리다가 처리 결과가 완료되면 다시 응답을 보낸다.
- 기존 업무 처리가 완료되기 전, 또 다른 request가 있으면 새로운 쓰레드가 업무를 시작한다.
- 동시 request가 많은 경우, 많은 쓰레드가 필요하게 되어 서버 과부화가 일어난다.
- 위 그림에서 어플리케이션에 커널에 System Call 을 보낸 후, 커널은 파일을 읽기 위한 동작을 수행하기 시작하고, 어플리케이션은 커널이 파일을 다 읽을 때까지 기다려야 한다. 이 상태를 어플리케이션이 Block되었다고 표현하며, 실제로 이 시간 동안 어플리케이션은 아무것도 하지 않는다.
- 시분할을 통한 멀티 쓰레드로 동시 여러 작업들을 처리한다.
이벤트 루프 기반의 비동기 방식 (Non-Blocking I/O)
- 작업을 요청하면서 그 작업이 완료되었을 때, 어떤 작업을 진행할 지에 대한 콜백함수를 지정하여 동작이 완료되었을 때 해당 콜백함수가 실행되는 방식의 동작 방식
- 위의 그림과 같이 설명하자면, 클라이언트가 웹 서버에 HTTP 요청을 하게 되면 서버에서는 이벤트 루프가 돌고 있다가 요청을 감지하고 알맞을 작업을
워커 스레드
를 생성하여 실행합니다. 이 때 이벤트 루프는 해당 워커 쓰레드가 작업을 마친 뒤 그 결과와 함께 응답할 때 까지 기다리는 것이 아닌 바로 루프로 복귀하여 다른 요청을 기다리게 됩니다.
- 즉, 이벤트 루프는 어떤 요청이 발생하면 그 작업에대해 쓰레드 실행만 일으킵니다. 이후 작업을 할당받았던 해당 쓰레드가 모든 작업을 미치면, 이리 전달받은 콜백 함수를 실행하여 이벤트 루프로 응답, 이벤트루프가 이를 실행하여 클라이언트에게 결과를 보내줍니다.
- Node.js로 개발된 프로세스는 이벤트 큐에 등록된 새로운 이벤트를 탐지합니다.
- 동시 request가 오더라도 처리가 완료될 때 까지 기다리지 않아도 되기에 서버 부하가 적습니다.
Node.js의 Thread Pool
Node.js는 애플리케이션 자체는 단일 스레드로 실행하지만, Background에서 thread pool을 구성해 작업을 수행합니다. thread pool을 관리하는 것은 개발자가 아닌 플랫폼이 합니다.
개발자는 스레드 하나를 관리하듯 프로그래밍하면 플랫폼이 여러 스레드를 효율적으로 운용합니다.
4. NPM을 통한 방대한 모듈 제공
- 모듈이란 애플리케이션을 구성하는 하나의 개별적 요소를 뜻합니다.
- NPM이라는 설치 관리자를 통해 쉽게 모듈을 설치 및 관리를 할 수 있습니다.
- 모듈은 파일로 구성되어 있으며, 필요한 모듈을 import 하여 원하는 모듈만 사용이 가능합니다.
- Node.js의 보급에 큰 영향을 끼쳤습니다.
정리
Node.js의 특징
- Node.js는 Single-Thread의 non-blocking I/O 이벤트 기반 비동기 방식으로 작동한다.
- 사용자의 요청은 한 곳(단일 스레드)에서 받지만, 실질적인 작업은 멀티쓰레드로 운영하여 결과를 구현한다. (Thread Pool)
- 단일 스레드이기에 메모리 사용량의 변화가 크지 않다.
- 따라서 대규모 네트워크 프로그램을 개발하기 적합한 형태이다.
- 하지만 스레드 하나가 오류가 발생되면 전체가 문제가 생긴다.
- 단일 스레드이기에 메모리나 리소스 등이 많이 필요한 작업을 수행하는 웹서비스에 맞지 않는다.
Node.js 작동 원리
- 입출력은 이벤트 루프 기반의 싱글 스레드, 실질적인 작업은 멀티 스레드로 실행한다.
- 푸드코트를 예로 들어 비유를 해 보자면,
- 주문은 한 곳에서 받고, 실질적인 요리는 각 식당에서 만든다.
- 음식이 완료되면 각 식당에서 호출벨을 통해 손님을 부르고, 손님은 음식을 픽업하게 된다.
- 여기서 계산을 담당하는 작업이 싱글 스레드이고, 각 요리를 완성해 벨을 호출하는 식당들은 thread pool을 통한 멀티스레드 비동기 방식이다.
- 입력은 하나의 스레드에서 받지만, 순서대로 처리하는 방식이 아닌 먼저 처리된 결과 값을 이벤트로 반환해 주는 방식이 Node.js가 사용하는 싱글 스레드 비동기 방식이다.
Node.js가 어울리는 웹서비스
- 간단한 로직
- 대량의 클라이언트가 접속하는 서비스(입출력 많음)
- 빠른 개발 요구
- 빠른 응답시간 요구
- 비동기 방식에 어울리는 서비스 (ex. 스트리밍 서비스, 채팅 서비스)
Node.js가 어울리지 않는 웹서비스
- 단일 작업이 오래 걸리는 서비스
- 로직 복잡도가 높은 경우
참고문서
https://edu.goorm.io/learn/lecture/557/한-눈에-끝내는-node-js/lesson/21763/이벤트-기반-비동기-방식
https://seoyeonkk.tistory.com/entry/Nodejs-의-특징-및-장단점