NodeJS 백엔드란? V8엔진과 이벤트 루트

Node JS는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임입니다.- 노드 공식 사이트

위와 같이 노드를 통해 다양한 자바스크립트 애플리케이션을 만들고 실행할 수 있으며, 서버를 실행할 때 가장 많이 활용되고 있습니다.

NodeJS 소개

NodeJS는 자바스크립트를 런타임으로 실행할 수 있는 자바스크립트 실행기입니다.

  • 노드는 JavaScript를 서버에서도 사용할 수 있도록 만든 JavaScript 런타임입니다.
  • 노드는 웹 서버와 같이 확장성 있는 네트워크 프로그램을 제작하기 위해 만들어졌습니다.
  • 노드는 V8엔진 위에서 동작하는 자바스크립트 환경입니다.
  • 단일 스레드 특징을 가지고 있으며, 비동기 프로그래밍을 지원합니다.
  • 논블로킹으로 요청을 처리하며 메모리 및 시간을 효율적으로 사용합니다.
  • 웹 서버에서 아파치 등의 별도 소프트웨어 없이 동작합니다.
  • 정적인 홈페이지가 아니라 다양한 데이터가 변해가는 사이트를 만들 수 있습니다.
NodeJS 구성요소와 동작 방식
https://sjh836.tistory.com/149

NodeJS 특징

NodeJS가 가진 특징으로 V8과 더불어 libuv라는 라이브러리를 사용합니다. 

대표적인 특징은 이벤트 기반으로 동작한다는 점과 Non-Blocking I/O 모델을 가진다는 점입니다. 여기서 나온 이벤트 기반(Event-drivec)이란 이벤트가 발생할 때 미리 지정해 둔 작업을 수행하는 방식을 의미합니다.

자바스크립트의 V8엔진은 비동기 처리를 할 수 없기 때문에 libuv 라이브러리를 이용해 비동기 처리를 진행합니다. 여기서 libuv는 이벤트 기반으로 비동기를 처리하는데 이벤트가 발생할 때 미리 지정해 둔 작업을 수행하는 방식을 사용합니다.

이것을 이벤트 리스너에 콜백 함수를 등록한다고 표현하죠.

또 다른 특징으로 노드JS는 싱글 스레드로 처리한다는 특징을 가지고 있습니다. 여기서 오해가 있을 수 있는데, 노드 자체는 멀티 스레드로 동작합니다. 다만 우리가 제어 가능한 스레드가 하나이기 때문에 싱글 스레드 처리라고 합니다. 우리가 활용할 수 없는 스레드는 수에 넣지 않습니다. 노드는 스레드 대신 프로세스 자체를 복사해 여러 작업을 동시에 처리하는 멀티 프로세싱 방식을 채택했습니다. js 언어 자체가 싱글 스레드 특징을 가지고 있기 때문입니다.

마지막으로 앞서 말한 Non-Blocking I/O에 대한 설명입니다. 노드는 싱글 스레드이고, 작업이 오래 걸리는 I/O 작업을 Non-Blocking으로 처리합니다. 그래서 I/O 작업이 시작되더라도 바로 다음 작업을 시작할 수 있기 때문입니다. 어차피 I/O에서 따로 작업을 진행하기 때문에 기다릴 필요가 없다고 판단한 거죠.

이렇듯 싱글 스레드와 논 블로킹 모델 특징 때문에 노드는 가볍고 효율적으로 자원을 사용할 수 있다는 장점을 가졌습니다. 대신 싱글 스레드 자체에 오류가 생기면 처리를 하기 어렵고, 단일 서버로는 현재 나온 CPU의 자원을 모두 활용하지 못한다는 단점이 있습니다. 이런 단점을 커버하기 위해 cluster 모듈과 pm2 패키지를 활용할 수 있습니다.

V8 엔진이란?

V8 엔진은 구글이 주도하여 C++로 작성된 고성능 자바스크립트 & 웹 어셈블리 엔진입니다. V8 엔진은 오픈소스이기 때문에 Github에서 코드를 받아볼 수 있으며, Chrome과 NodeJS, ECMAScript와 Web Assembly에서 사용되고 있습니다.

img
JSConf EU 2017에서 발표한 Franziska Hinkelmann님의 자료

위 그림은 V8 엔진이 동작하는 방식에 대한 간략한 이미지입니다. 각각에 대한 설명은 길어지기 때문에 가볍게 이야기하겠습니다.

먼저 자바스크립트 코드를 Parser에 보내 분해를 진행합니다.
그다음 분해된 토큰으로 AST Tree를 만듭니다.
이걸 Interpreter Ignition에게 전달하고 ByteCode로 번역 후 실행합니다.
그 다음 TurboFan에게 최적화 컴파일을 진행시킵니다.
이렇게 되면 최적화된 코드를 ByteCode를 대신해서 실행됩니다. 

위와 같은 순서로 진행되며, 자바스크립트 코드를 실행하게 됩니다. 이와 함께 libuv를 통해 노드 JS가 동작하게 됩니다.

이벤트 루프

이벤트 루프는 NodeJS의 핵심 개념입니다. 노드의 특징을 이야기할 때 이벤트 루프를 빼놓을 수 없기 때문입니다. 

이벤트 루프 안에는 다양한 이벤트 큐가 존재하며 앞서 본 이미지처럼 libuv 라이브러리 안에서 노드가 전달해 준 요청을 처리하고 있습니다.

img
https://evan-moon.github.io/2019/08/01/nodejs-event-loop-workflow/

이벤트 루프 안에는 다양한 큐를 가지고 있으며, 모든 박스가 Queue라고 이해하면 됩니다. 각 단계별로 처리 방식이 다르며, 가운데에 있는 nextTickQueue와 microTaskQueue는 이벤트 루프의 일부가 아닙니다. 이 큐에 들어간 작업은 어떤 큐에서든 실행 가능합니다.

이벤트 루프는 Call stack에서 넘겨준 요청이나 Task Queue, MicroTask Queue에서 넘겨주는 다양한 이벤트를 단일 스레드로 처리합니다. 여기서 나오는 것이 비동기와 Non-Blocking I/O 처리입니다. 그렇기 때문에 많은 요청을 빠르게 처리할 수 있게 됩니다.

img
https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

위에 있는 Task(Macrotask Queu) Queue와 MicroTask Queue는 각자 처리하는 요청이 다릅니다. 

Task Queue 같은 경우 setTimeout(), setInterval(), setImmediate()와 같은 task를 넘겨받습니다.

MicroTask Queue는 Promise, async/await, process.nextTick, Object.observe와 같은 비동기 호출을 넘겨받습니다.

마지막으로 Animation Frames는 브라우저 렌더링과 관련된 task를 넘겨받는 Queue입니다. 

처리되는 우선순위를 보면 첫 번째는 MicroTask Queue 입니다. 비동기 처리가 가장 먼저 처리되며 그다음 Animation Frames가 처리됩니다. 마지막으로 Task Queue가 처리됩니다. 처리 순서를 알고 있다면 코드를 작성할 때, 어떤 기능이 먼저 실행되고 처리되는지 알 수 있습니다.

// 1. 실행
console.log("script start");

// 2. task queue로 전달
setTimeout(function () {
  // 10. task 실행
  console.log("setTimeout");
}, 0);

//3. microtask queue로 전달
Promise.resolve()
  .then(function () {
    // 6. microtask 실행
    console.log("promise1");
  }) // 7. microtask queue로 전달
  .then(function () {
    // 8. microtask 실행
    console.log("promise2");
  });

//4. AnimationFrame으로 전달
requestAnimationFrame(function () {
  //9. animation frame 실행
  console.log("animation");
});

//5. 실행
console.log("script end");
이벤트 루프 큐 설명

위 코드는 앞서 말한 Queue 실행 순서를 보여주는 코드입니다. promise가 먼저 실행되고 animation, setTimeout 순으로 실행되는 걸 볼 수 있습니다.

정리

이번 글에서는 NodeJS의 특징과 핵심 기능에 대한 내용을 다뤘습니다. V8 엔진과 이벤트 루프는 분리되어 있으며 libuv를 통해 다양한 요청을 처리한다는 것을 알 수 있었습니다. 각 기능별 자세한 사항은 추후 따로 다뤄볼 예정입니다. 각 주제만 다뤄도 하나의 글이 완성되기 때문에 NodeJS와 연관된 핵심 내용만 이야기하고 마무리하도록 하겠습니다.

참고 문헌

https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

https://velog.io/@titu/JavaScript-Task-Queue%EB%A7%90%EA%B3%A0-%EB%8B%A4%EB%A5%B8-%ED%81%90%EA%B0%80-%EB%8D%94-%EC%9E%88%EB%8B%A4%EA%B3%A0-MicroTask-Queue-Animation-Frames-Render-Queue

https://evan-moon.github.io/2019/06/28/v8-analysis/

https://sjh836.tistory.com/149

https://hanamon.kr/nodejs-%EA%B0%9C%EB%85%90-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0/

https://evan-moon.github.io/2019/08/01/nodejs-event-loop-workflow/#%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%8A%94-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%97%94%EC%A7%84-%EB%82%B4%EB%B6%80%EC%97%90-%EC%9E%88%EB%8B%A4

https://blog1.westagilelabs.com/node-js-basics-82e1c2cda96

Leave a Comment