싱글스레드 vs 멀티스레드 (Node.js)

June·2022년 8월 14일
24

우테코

목록 보기
69/84
post-thumbnail

학습 배경

CS 스터디에서 프로세스와 스레드 차이에 대해 발표를 했다. 그리고 언제 멀티스레드를 써야할까라는 질문에 엔터프라이즈 환경에서 대규모 요청이 오는 프로젝트라면 성능을 위해 멀티스레드를 사용할 것 같습니다라고 답을 했다. 하지만 답을 하고 나서 스스로 찜찜한 부분이 있었다. Node.js는 싱글 스레드라고 알고 있는데 그러면 노드를 쓰는 기업들은 왜 쓰는 것이고 어떻게 트래픽 감당이 가능한 것일까라는 궁금증이 들었다.

토미와 팀 점심을 먹은 후 산책을 하면서 이 궁금증에 대해 이야기 해봤고 동키콩까지 도와줘서 이벤트루프와 큐를 통해 비동기를 지원한다는 것을 알게되었다.

그런데 마침 이번 근로 카드뉴스 제작 주제가 유세지의 Node.js였다. 그래서 유세지의 영상을 보면서 차이에 대해 간략하게라도 알게되었다.

멀티스레드 vs 싱글스레드

보통은 멀티프로세스와 멀티스레드를 비교하는 질문들을 받았다. 멀티스레드를 이용하면 프로세스 내부의 자원들을 공유해서 사용할 수 있다. (그림에서 보듯 레지스터와 스택은 제외다. 참고로 지역변수는 스택에 저장된다. 지역변수가 동시성 이슈로부터 자유로운 이유다). 그래서 멀티프로세스 대비 컨텍스트 스위칭 비용이 저렴하다. 하지만 개발할 때 동시성 이슈에 대해서 고려를 해야하며, 데드락 상태에 빠질 수 있다. 또 스레드를 많이 생성하면 메모리 낭비로 이어질 수 있다.

이러한 단점들이 싱글스레드 환경에서는 장점으로 바뀐다. 동시성 이슈에 대해 걱정할 필요가 없으며 데드락을 고려하지 않아도 된다.

자바스크립트와 Node.js

자바스크립트는 싱글스레드 환경이다. 처음에는 여기서 이해가 되지 않았다. 그러면 자바스크립트에서는 비동기를 어떻게 처리하는거지? 자바 환경이라면 기존의 흐름을 이어가는 스레드가 작업을 하다가 비동기 작업을 만나면 새로운 스레드가 시간이 걸리는 작업을 기존 스레드와 동시에 해줄 수 있을 것이다.

Node.js는 싱글스레드를 효율적으로 사용할 수 있는 이벤트 루프 방식을 선택했다.

코드가 진행되다가 비동기 작업을 만나면 이 작업을 처리해주는 대상들에 위임한다. 그리고 대상들이 작업을 끝내면 전달받은 콜백을 큐에 넣어준다.

이렇게 실행중인 작업이 존재하는지, 큐에 task가 존재하는지 를 판단하고, 큐의 작업을 콜스택에 옮기는 일을 이벤트루프가 담당한다. Event Loop 는 이 작업을 계속 반복한다.

Node.js 내부구조

노드의 내부 구조인데 libuv는 비동기 작업을 수행하는 C 기반 라이브러리라고 한다. 자체적으로 네 개의 쓰레드를 가진 쓰레드 풀을 가지고 있다고 한다. 이벤트루프에 던져진 비동기 작업들은 일반적으로 libuv가 아닌 시스템 커널에서 처리 된다. 즉 네트워크와 소켓 관련 작업은 시스템이, 파일 입출력은 libuv가 직접 처리한다.

결과적으로 Node.js자체는 완전한 싱글스레드 환경이 아니고 자바스크립트를 실행하는 환경만 싱글스레드라는 생각이 들었다.

추가적으로 처음에 궁금했던, 싱글스레드인데 어떻게 대규모 트래픽을 받을 수 있을까에 대해 찾아봤다. 첫 번째로 노드가 완전한 싱글스레드 환경이 아니다. 하지만 코드를 돌리는 부분이 싱글스레드인 것은 맞고 그래서 인프라적으로 분산처리가 중요하다고 한다.

노드와 자바스크립트에 대해 잘 몰라서 그런지 이해하는게 조금 힘들었네요. 틀린 부분있으면 언제든지 가르쳐주세요

2개의 댓글

comment-user-thumbnail
2022년 8월 22일

좋은 글 감사합니다 :)

답글 달기
comment-user-thumbnail
2022년 10월 1일

멋진 카드 뉴스 만들어주셔서 감사합니다 👏👏

답글 달기