Node.js 는 'Single-Thread' 인가?

Seungmin Shin·2021년 11월 17일
4

Node.js 는 싱글스레드 (Single-Thread) 인가?

Intro

이 질문에 대해 답을 내리기 위해 웹상의 여러 글을 찾아보고, 읽어보았다.
그리고 나서 느낀점이 무엇이냐면,

의외로 "질문의 의도를 다시 파악해 보아라." 였다.

이게 무슨 뜻이냐면, 처음 이 질문을 받고 이 질문에 대해 대답을 하기 위해 여러 정보를 찾기 전에
내가 가지고 있었던 목적은 "node.js 가 멀티쓰레드인가 싱글쓰레드 인가" 였다.

하지만 어느정도 정보를 찾다보니 잘못된 방향으로 정보를 찾으려 했다는것을 알게 되었다.

결론을 먼저 말해보자면 "Node.js 는 궁극적으론 멀티스레드" 이다.
만약 이 글을 읽는 당신이 원하던 대답이 단지 이것이라면 여기까지만 읽고 돌아가도 좋다.

하지만 위에서 말했듯이 당신은 누군가로부터 "node.js 가 싱글스레드인가?" 라는 질문을 받았거나,
아니면 이 질문에 대답을 해야하는 과제를 받았기 때문이라고 생각을 한다. 만약 그렇다면 이 글을
더 읽는 편이 좋을 듯 하다. 설마 이 질문이 그렇게 간단한 의미를 가지고 있을리가 없지 않은가?

이제 본격적으로 이 대답을 하기에 앞서 그렇다면, 도대체 저 질문의 의도는 무엇일까? 가 궁금할 수 도 있다.

음, 지금 바로 그 의도를 알기에는 애매할 수도 있지만 일단 궁금하다면 질문의 큰 의도정도는 알고가도
좋을 것 같긴하다, 이것 또한 나의 개인적인 의견임을 참고해주길 바란다.

내가 생각한 이 질문의 의도는
"Node.js 가 싱글스레드라고 불리우는 이유는 무엇인가?" 로 해석이 되었다.

node.js 가 멀티스레드인지 싱글스레드인지는 검색 몇번만 하면 바로 나오는 사실이다.
그리고 굳이 멀티스레드인가? 가 아닌, 싱글스레드 인가? 라는 질문을 던진걸로 보아
node.js가 싱글스레드로 인지가 많이 되고 있다는 사실을 알려준다. 멀티스레드인데도 말이다.

이 질문은 그것을 물어보고 있다, 멀티스레드로 알려져있는 node.js 가 왜 싱글스레드라는 말을 듣고 있는지?

이제부터 그 이유에 대해 설명하겠다. 서론이 좀 길었다. 그래도 질문에 대한 의도를 조금은 자세하게
짚고 시작을 해야 저 질문에 대해 어떤식으로 답변을 해야하는지가 나오기 때문이다.


Node.js

Node.js의 개념

일단 Node.js의 개념을 먼저 잡고 시작을 하자, 지피지기면 백전백승 아닌가?

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

런타임: 프로그래밍 언어가 구동되는 환경

Node.js 가 나오기 전에는 자바스크립트 런타임은 브라우저 밖으로 나올 수 없었다.
이때 당시까지만 해도 자바스크립트 언어는 브라우저환경을 조성하기 위해서만 쓰여졌다는 뜻이다.

하지만 Node.js 가 나오면서 자바스크립트 언어를 사용해 프론트엔드와 백엔드의 환경 모두에서
작업이 가능해지게 되었다. 이건 혁명이었고 node.js 는 개발자 사이에서 미친듯이 확장해 나가게 되었다.
왜 혁명이라고까지 표현이 되었는지는 node.js 개념을 설명하는 많은 블로그에 설명이 되어있을테니
자세하게 짚고가진 않도록 하겠다, 우리는 지금 다른것을 다루고 있기 때문이다.

아무튼 간단하게 설명을 하자면, "Node.js는 자바스크립트를 브라우저 밖에서도 실행시켜주는 실행기"
라고 이해하면 되겠다.

이벤트 기반

Node.js는 V8엔진과 더불어 libuv (리버브) 라는 비동기 이벤트처리 라이브러리를 사용한다.
이것이 곧 Node.js 의 특성인 이벤트기반, 논블로킹 I/O 모델의 기반이된다.

여기서 이벤트기반 이란, 이벤트가 발생할때 미리 저장해 둔 작업을 수행하는것을 말한다.

자바스크립트는 기본적으로 싱글스레드 기반이기때문에 동기적인 방식으로 동작하게 된다,
이 말은 곧 동시성을 요구하는 어플리케이션에는 썩 좋은 환경은 아니라는 것이다.
그렇기 때문에 Node.js 는 이벤트나 콜백함수를 활용하여 자바스크립트의 싱글 스레드 방식이나,
비동기적 처리방식을 지원한다. 이러한 이유로 이벤트기반 방식을 사용한다.

간단하게 플로우를 설명하자면, 어떠한 이벤트가 발생했을때, 어떤 동작을 할지 등록을 해둔다음
이것을 이벤트 리스너에 콜백으로 등록을 해둔다. 이후에 이벤트가 발생하면 리스너에 등록해 둔 콜백함수를
실행하게 된다. 이러한 이벤트는 계속해서 돌고돌며 실행되기에 이것을 이벤트 루프라고 한다.


그래서 Node.js는 왜 싱글스레드로 불리는가?

Node.js 의 호출스택 구성

이 해답을 찾기 위해서 Node.js 의 호출스택을 확인해 보자.

이 사진은 전체적인 호출 스택을 이미지 화 한것이다. 5가지의 구성으로 나뉘어져 있는것을 볼 수 있다.
하나씩 설명해보자면

  1. Memory Heap: 구조화 되지 않은 객체 (변수, 함수) 등이 담겨있는 공간.
  2. Call Stack: 실행될 코드들을 한줄 단위로 담은 공간.
  3. Web APIs (Background): 비동기적 처리를 위한 공간. (Background는 node에서 쓰는명칭)
  4. Callback Queue: 비동기 처리가 끝난 후 호출스택으로 넘어가야할 콜백함수를 담아두는 공간.
  5. Event Loof: Queue에 할당된 순서에 맞게 CallStack 으로 넘겨주는 역할을 한다.

이 호출스택이 어떤 방식으로 동작하는지는 다른 게시글에서 다루겠다.
왜냐하면 이번 포스팅의 목적은 Node.js 가 왜 싱글스레드로 불리는지가 목적이기 때문이다.

자 이것이 바로 Node.js 가 멀티쓰레드로 인지되는 이유이다.

무슨말인고 하니, 자바스크립트의 기본은 싱글스레드를 기반으로 하는 동기적인 처리를 하는 것이라고 했는데
이 구성은 비동기식 처리가 가능한 구성이 되었다, 이것은 위에서 설명했던 비동기 I/O 작업을 통한
논블로킹 모델로 사용이 가능해졌기 때문이다. 하나의 스레드로 동작하게 되지만, 서로 블로킹하지 않는다.

여기서 더해 클러스터링을 통하여 프로세스를 늘려 마치 멀티스레드인 것 처럼 사용하기 때문에
마치 Node.js 가 멀티스레드 인것 처럼 느껴지는 것이라고 생각한다.

사실 나는 이 포스팅을 하며 초반에 이미 Node.js 가 싱글스레드 기반이라고 이야기를 했다.
왜냐하면 Node.js 는 Main 스레드 단 한군데에서만 자바스크립트를 실행하기 때문이다.
이 부분에 대해 오해가 많아 멀티스레드라고 헷갈리곤 하던데, 자바스크립트를 실행하는 스레드와 이벤트루프를
실행하는 스레드가 달라 2개의 스레드로 동작하는것이 아니냐? 라는 내용이었던 것 같다.

찾아보니 그렇지 않고 하나의 스레드에서 두가지가 모두 이루어진다고 한다.
개발자의 피셜이니 믿어도 될듯 하다.

그럼 오해가 풀렸으니, 싱글스레드로 확정인가? 그것 또한 아니다, Node.js는 완전한 싱글스레드는
아니라고 한다, 이건 오해가 아닌 사실인데, 논블로킹 비동기 I/O 작업을 담당하는것이 libuv 내의
Thread pool (스레드 풀) 이라는 곳에서 담당하는데, 이 스레드 풀이 멀티 스레드로 이루어져 있기때문에Node.js 가 완전한 싱글 스레드는 아니라고 하는 것 이다, 어쨌든 이 libuv 도 Node.js 의
일부분이기에..

결론

Node.js 는 궁극적으로는 멀티스레드의 개념을 가지고는 있지만, 메인으로 사용되는 자바스크립트 환경
자체는 싱글스레드로 사용이 된다, 하지만 Node.js 의 특징인 논블로킹 비동기 I/O 모델로 인해
마치 멀티 스레드처럼 사용이 가능하여 이러한 논쟁이 가능하게 끔 한것이 아닌가 싶다.

그리고 실질적으로도 Node.js 를 구성하는 libuv 의 Thread pool 이 멀티 스레드로 이루어져 있기에
완전히 싱글스레드라고 할 수 도 없다, 그래서 나의 의견을 말하자면

"Node.js는 완전하지 않은 싱글스레드" 라고 정리하겠다.

profile
Frontend Developer

0개의 댓글