Node.js - 기본 개념


이 포스트는 Node.js(Mac 기준) 의 기본 개념과 Node.js 을 시작하기에 앞서 알아야 할 내용들에 대해 기술한다.

  • Node.js 개념
    • Event-driven (이벤트 기반)
    • Non-Blocking I/O
    • Single Thread
  • Node.js 의 활용
  • Node.js 환경 설정 (Mac)

1. Node.js 개념

Node.js란?
Chrome V8 Javascript 엔진으로 빌드된 Javascript 런타임

Node.js (이하 노드) 는 Javascript 런타임이며,
여기서 런타임이란 특정 언어로 만들어진 프로그램들을 실행할 수 있는 환경을 말한다.
(Node.js = Javascript 실행기)

브라우저는 Javascript 런타임을 내장하고 있기 때문에 Javascript 코드를 실행할 수 있지만 브라우저 외의 환경에서는 Javascript 속도 문제들이 존재했다.

2008년 구글이 V8 엔진을 사용하여 출시한 크롬은 다른 Javascript 엔진과 달리 매우 빨랐고, 오픈 소스로 코드를 공개함으로써 노드 프로젝트를 시작하게 되었다.

노드는 V8 과 더불어 libuv 라이브러리를 사용하는데
libuv 라이브러리는 Node.js 의 특징인 Event-driven, Non-Blocking I/O 모델을 구현하고 있다.

개발환경: macOS, node 16.6.0


1.1. Event-driven (이벤트 기반)

Event-driven
이벤트가 발생할 때 미리 지정해 둔 작업을 수행하는 방식

특정 이벤트가 발생할 때 수행할 작업을 등록해두는 작업을 이벤트 리스너에 콜백 함수를 등록한다고 표현한다.

Event loop (이벤트 루프)
여러 이벤트가 동시에 발생했을 때 어떠한 순서로 콜백 함수를 호출할 지 판단
즉, 이벤트 발생 시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 순서를 결정하는 역할
노드가 종료될 때까지 이벤트 처리를 위한 작업을 반복하기 때문에 loop 라고 부름

백그라운드
setTimeout 과 같은 타이머나 이벤트 리스터들이 대기하는 곳

태스크 큐(콜백 큐)
이벤트 발생 후 백그라운드에서는 태스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보냄


1.2. Non-Blocking I/O

Non-Blocking
이전 작업이 완료될 때까지 대기하지 않고 다음 작업을 수행

Blocking
이전 작업이 완료되어야만 다음 작업을 수행

이벤트 루프를 잘 활용하면 오래 걸리는 작업을 효율적으로 처리할 수 있는데
예를 들어 I/O 작업 (파일 읽기/쓰기,폴더 생성 등 파일 시스템 접근이나 네트워크를 통한 요청 작업) 은 Non-Blocking 방식으로 처리할 수 있다.

노드는 I/O 작업을 백그라운드로 넘겨 동시에 처리할 수 있기 때문에 동시 처리가 가능한 작업들은 최대한 묶어서 백그라운드로 넘겨야 시간을 절약할 수 있다.
동시에 처리될 수 있는 I/O 작업이라도 Non-Blocking 방식으로 코딩하지 않으면 의미가 없다.

setTimeout(callback, 0) 은 Non-Blocking 으로 만들기 위해 사용하기도 하는데
호출 스택에서 백그라운드로 setTimeout 을 보내고, 백그라운드는 0초 후에 태스트 큐로 callback 함수를 보내게 되는 구조이다.
setTimeout(callback, 0) 말고 setImmediate 가 더 자주 사용되는데 이는 나중에 알아볼 예정이다.

주의할 것은 노드는 Single Thread 이기 때문에 Non-Blocking 방식으로 작성했더라도 그 코드가 모두 개발자가 작성한 코드라면 전체 소요 시간이 짧아지는 것이 아니라 실행 순서만 바뀐다는 것이다.
오래 걸리는 작업이 있을 때 Non-Blocking 을 통해 실행 순서를 바꿔줌으로써 그 작업 때문에 다른 작업들이 대기하는 상황을 막는 것이다.

Non-Blocking 을 동시성과 헷갈려서도 안된다.
동시성동시 처리가 가능한 작업을 Non-Blocking 처리해야 얻을 수 있다.


1.3. Single Thread

Single Thread 란 말 그대로 Thread 가 하나뿐이라는 의미이다.

Process
운영체제에서 할당하는 작업의 단위
프로세스 간에는 메모리 등의 자원을 공유하지 않음

Thread
프로세스 내에서 실행되는 흐름의 단위로 프로세스는 스레드를 여러 개 생성하여 여러 작업을 동시에 처리할 수 있음
스레드들은 부모 프로세스의 자원을 공유하고, 같은 주소의 메모리에 접근이 가능하므로 데이터 공유가 가능

엄밀히 말하면 노드는 싱글 스레드는 아니다.
노드를 실행하면 하나의 프로세스가 생성되고, 그 프로세스는 내부적으로 여러 개의 스레드들을 생성하는데 이 중에서 개발자가 직접 제어할 수 있는 스레드는 하나이기 때문에 노드는 싱글 스레드라고 하는 것이다.

Thread Pool 과 Worker Thread
노드가 싱글 스레드로 동작하지 않는 두 가지 경우가 있는데 스레드 풀과 워크 스레드가 그 경우이다.

Thread Pool
노드는 특정 동작을 수행할 때 스스로 멀티 스레드를 사용
예) 암호화(crypto), 파일 입출력, 압축(zlib) 등

Worker Thread
노드 12 버전에서 안정화된 기능
CPU(연산) 작업이 많은 경우 워커 스레드를 사용하면 됨

멀티 스레드 방식이 무조건 좋은 것은 아니다. 처리할 작업이 줄어들었을 경우 놀게 되는 스레드가 발생하고, 이러한 스레드를 destroy 하는 데에도 비용이 들어가기 때문이다.

또한 멀티 스레드 방식으로 코딩하는 것은 난이도가 높기 때문에 상황에 따라 멀티 프로세싱 방식을 사용하기도 한다.
아래와 같은 기준으로 방향성을 정하는 것도 좋다.

  • I/O 요청이 많을 경우는 더 효율적이고 난이도가 비교적 낮은 멀티 프로세싱 방식으로 진행
    예) cluster 모듈, pm2 패키지에서 멀티 프로세싱을 가능하게 해줌
  • CPU 작업이 많은 경우는 난이도는 높지만 멀티 스레딩 방식으로 진행
    예) worker_threads

2. Node.js 의 활용

위에서 노드는 기본적으로 싱글 스레드와 논 블로킹 모델을 사용한다고 하였다.

서버에는 기본적으로 I/O 요청이 많이 발생하므로 노드를 서버로써 사용하는 경우가 많다.
이말은 CPU 부하가 큰 작업에는 노드가 부적합하다는 의미이기도 하다.

노드는 libuv 라이브러리를 이용하여 I/O 작업을 논 블로킹 방식으로 처리하기 때문에 하나의 스레드가 많은 수의 I/O 를 처리할 수 있다.

노드는 네트워크나 DB, 디스크 작업같은 I/O 에 특화되어 있기 때문에 갯수는 많지만 크기는 작은 데이터를 실시간으로 주고 받는 실시간 채팅이나 주식 차트, JSON 데이터를 제공하는 API 서버에 사용하기 좋다.

노드 12 버전부터 워커 스레드 기능이 안정화되어 멀티 스레드 작업이 가능은 하지만
멀티 스레드는 싱글 스레드에 비해 난이도가 높고 C, C++, Rust, Go 와 같은 언어에 비해 아직 속도가 많이 느리다.
따라서 멀티 스레드 기능이 있지만 미디어 처리, 대규모 데이터 처리처럼 CPU 를 많이 사용하는 작업을 위한 서버로 노드는 적합하지 않다.
만일 이러한 작업에 굳이 노드를 사용해야 한다면 AWS Lambda 나 Google Cloud Functions 와 같은 서비스에서 노드로 CPU 를 많이 사용하는 작업처리를 지원하므로 이 부분을 알아보는 것이 좋다.

노드에는 웹 서버가 내장되어 있지만 서버 규모가 커지게 되면 결국 nginx 등의 웹 서버를 노드 서버와 연결해야 한다.
노드는 생산성은 좋지만 (자바스크립트라는 하나의 언어로 프론트와 서버를 모두 개발하므로) nginx 처럼 정적 파일을 제공하거나 로드 밸런싱에 특화된 웹 서버에 비해서는 속도가 느리다.

정적인 컨텐츠를 주로 제공하는 서버로 노드를 사용할 때 Nunjucks(넌적스), Pug(퍼그), EJS 와 같은 템플릿 엔진을 통해 다른 언어와 비슷하게 콘텐츠를 제공하는 방법도 있다.

지금까지 서버로서의 노드의 활용에 대해 알아보았다.
하지만 노드는 자바스크립트 런타임이므로 용도가 서버에만 한정되어 있지 않다.

노드 기반 대표적인 웹 프레임워크로는 Angular, React, Vue 등이 있다.
모바일 개발 도구로는 React Native 가 많이 사용되는데 페이스북, 인스타그램, 핀터레스트 등이 리액트 네이티브를 사용하여 모바일 앱을 운영중이다.
데스크탑 개발 도구로는 Electron 이 대표적인데 Atom, Slack, Discord, Visual Studio Code 등이 일렉트론으로 만들어진 대표적인 프로그램들이다.


3. Node.js 환경 설정 (Mac)

Node.js 공홈 에 접속하여 Current 버전 (학습용이므로) 을 설치한다. (포스팅 작성 기준 16.6.0 버전)

npm
노드 패키지 매니저

노드, npm 설치 확인

$ node -v
v16.6.0

$ npm -v
7.19.1

npm 버전 업데이트

$ npm install -g npm

# if an error occurs.
# This is an error that occurs when installing globally with -g appended.
$ sudo npm install -g npm

$ npm -v
7.20.3

환경 변수 목록 확인 및 PATH 환경 변수 추가

$ echo $PATH
Users/사용자/.rbenv/shims /Users/사용자/.rbenv/bin /usr/local/bin /usr/bin /bin /usr/sbin /sbin

$ export PATH=$PATH:추가경로

본 포스트는 조현영 저자의 Node.js 교과서 2판을 기반으로 스터디하며 정리한 내용들입니다.

참고 사이트 & 함께 보면 좋은 사이트






© 2020.08. by assu10

Powered by assu10