[Node.js] 노드 쉽게 설명하기

가영·2021년 2월 13일
1

노드의 공식 사이트에서는 노드를 다음과 같이 설명하고 있다.

Node.js는 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임이다 ...

자바스크립트 런타임

런타임은 특정 언어로 만든 프로그램들을 실행할 수 있는 환경을 뜻한다. 노드는 자바스크립트 런타임이라고 했다. 따라서 노드는 자바스크립트 프로그램을 컴퓨터에서 실행할 수 있게 해준다.

예전에는 자바스크립트 런타임이 인터넷 브라우저 밖에 없었다. (브라우저 외 환경에서 js를 실행하기 위한 여러 시도가 있었지만 속도 문제 때문에 큰 호응 X)

2008년 구글이 V8 엔진을 사용한 크롬을 출시한 것이 발단.

V8엔진은 당시 다른 자바스크립트 엔진과 달리 속도가 매우 빨랐다. V8엔진의 코드가 오픈소스로 공개되기도 했다. 자바스크립트 런타임의 속도 문제가 해결되자, 라이언 달이 2009년 V8 엔진 기반의 노드 프로젝트를 시작했다.

노드는 V8과 함께, libuv라는 라이브러리를 사용한다. V8과 libuv는 c와 c++로 구현돼있다. 이 때 사용자는 libuv를 직접 접근할 필요가 없다. 노드가 알아서 연결해주기 때문이다.

노드가 V8과 구분되게 하는 ~ !
libuv 라이브러리는 노드의 특성인

  • 이벤트 기반
  • 논블로킹 I/O 모델

을 구현하고 있다. 🙄


c/c++로 구현돼있는 위 두 가지 노드의 특징을 정확히 이해해보자.

이벤트 기반 (Event-driven)

이벤트 기반이라는 말은 특정 이벤트가 발생할 경우 미리 지정해둔 작업을 수행하는 방식을 뜻한다. 이벤트로는 클릭/네트워크 요청 등이 있겠지.

우리는 지금까지 이벤트 기반 시스템에서 특정 이벤트가 발생할 때 뭘 할지 등록하는 걸, Event listener에 callback 함수를 등록한다 고 표현한 것이다. 🤗

노드는 이벤트가 발생하면 이벤트 리스너에 등록해둔 콜백 함수를 호출한다. 발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면, 다음 이벤트가 발생할 때까지 대기하는 것이다.

이벤트 기반 모델에서는 이벤트 루프라는 개념이 등장한다. 여러 이벤트가 동시에 발생했을 때 어떤 순서로 콜백 함수를 호출할지 판단하는 애가 이벤트 루프다. 용어들을 더 정확히 정리를 해보자🙂

  • 이벤트 루프: 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행 순서를 결정하는 역할. 노드가 종료될 때까지 이 작업을 반복하기 때문에 루프라고 불린다.

  • 태스크 큐: 이벤트 발생 후! 호출돼야 할 콜백 함수들이 기다리는 공간. 콜백 큐라고도 불린다.

  • 백그라운드: 타이머 콜백, I/O 작업 콜백 또는 이벤트 리스너들이 대기하는 곳이다. 대기가 끝나면 함수가 태스크 큐로 감

아래 사진을 누르면 setTimeout을 예로 이벤트 루프를 설명하는 발표를 들을 수 있당. (12:52) 👇🏻 click!

main() 까지 모두 실행되어서 호출 스택이 비어야만! task queue에 있는 setTimeout의 콜백이 콜 스택에 들어갈 수 있다.

만약 위 동영상에서처럼 5초 후 콜백이 실행되게 setTimeout을 실행해도, 호출 스택에 함수들이 너무 많이 차 있으면 5초가 지난 후에도 콜백함수가 실행되지 않을 수 있다. 이것이 setTimeout의 시간이 정확하지 않을 수도 있는 이유다.


논블로킹 I/O

이벤트 루프를 잘 활용하면 오래 걸리는 작업을 효율적으로 처리할 수 있다. 오래 걸리는 함수를 백그라운드로 보내서 다음 코드가 먼저 실행되게 하고, 그 함수가 다시 태스크 큐를 거쳐 호출 스택으로 올라오기를 기다리는 방식이다.

그리고 이런 방식을 논블로킹 이라고 하는 거다.

모든 코드에서 논블로킹 방식이 좋은 것만은 아니지만! 노드 프로세스 외의 다른 컴퓨팅 자원을 사용하는 I/O 작업은 논블로킹 방식을 통해 시간적 이득을 많이 본다고 한다.

파일 시스템 접근(파일 읽기, 쓰기, 폴더 만들기 등)이나 네트워크 요청 같은 것들이 I/O 작업이라고 할 수 있다. 노드는 위와같은 I/O 작업을 할 때 논블로킹 방식으로 동작하여 시간을 절약하는 것이다...😉


블로킹 방식 code

function longRunningTask() {
  // 파일 시스템 접근이나 네트워크 요청 등 오래걸리는 작업~
  // ...
  console.log('작업 끝');
}
console.log('시작');
longRunningTask();
console.log('다음 작업');

콘솔 결과

시작
작업 끝
다음 작업

논블로킹 방식의 code

function longRunningTask() {
  // 오래 걸리는 작업 ~
  // ...
  console.log('작업 끝');
}
console.log('시작');
setTimeout(longRunningTask, 0);
console.log('다음 작업');

콘솔 결과

시작
다음 작업
작업 끝

setTimeout(콜백, 0)은 코드를 논블로킹으로 만들기 위해 사용하는 기법 중 하나인데, 사실 노드에서는 이거 말고 다른 방식을 주로 사용한다. (setImmediate(callback))

setTimeout(콜백, 0)

밀리초를 0으로 설정했으므로 바로 실행되는 것이 아닌가 착각할 수 있다.
하지만 브라우저와 노드에서는 기본적인 지연 시간이 있으므로 바로 실행되지 않는다! HTML5 브라우저에서는 4ms, 노드에서는 1ms의 지연 시간이 있다.


이벤트 기반, 논블로킹 모델과 함께 노드를 설명할 때 자주 나오는 용어가 있는데, 바로 싱글 스레드 이다.

싱글 스레드

자바스크립트와 노드에서 논블로킹이 중요해진 이유는 바로 싱글 스레드라는 특성 때문이다. 한 번에 한 가지 일밖에 처리하지 못하므로 블로킹 발생 시 다음 일을 처리하지 못하는 것이다.

노드 프로세스는 스레드가 하나이기 때문에 요청이 많이 들어오더라도 한 번에 하나의 요청을 처리한다. 블로킹이 심하게 일어나지만 않는다면! 하나로도 충분하다.

(근데 사실 노드 프로세스도 내부적으로는 스레드를 여러 개 가지고 있다. 하지만 우리가 직접 제어할 수 있는 스레드는 하나 뿐이라서 흔히 싱글 스레드라고 부르는 것이다.)

노드는! 스레드를 늘리는 대신, 프로세스 자체를 복사해서 여러 작업을 동시에 처리하는 멀티 프로세싱 방식을 택했다. 자바스크립트 언어 자체가 싱글 스레드 특성을 띠고 있기 때문이다.

이 때! 우리는 cluster 모듈과 pm2 패키지를 이용해 노드를 실행시킬 때 멀티 프로세싱 방식을 사용할 수 있다.😙

1개의 댓글

comment-user-thumbnail
2021년 8월 31일

잘 읽었습니다^^

답글 달기