Node.js의 동작 원리

Younha Lee·2026년 1월 15일

TIL

목록 보기
12/61

개요

내가 사용하는 노드에 대해 글로 정리할 필요가 있다고 생각이 들었어요.
Node.js의 동작 원리에서 가장 중요한 건 "싱글 스레드(Single Thread) 기반의 이벤트 루프(Event Loop)와 비동기 I/O(Non-blocking I/O)"에요.

저는 이벤트 루프를 중심으로 요즘 유행하는 식당으로 비유해볼게요.


노드 식당

Node.js 서버 (싱글 스레드, 이벤트 루프 방식)

  • 방식: 가게에 슈퍼 종업원(메인 스레드)이 딱 한 명 있어요.
  • 상황:
    1. 손님이 주문하면 주문만 받고 바로 주방(OS/커널)에 넘깁니다. (비동기)
    2. 요리가 나올 때까지 기다리지 않고, 즉시 다음 손님의 주문을 받으러 갑니다. (Non-blocking)
    3. 주방에서 "요리 나왔어요!(이벤트 발생)"라고 알리면, 그때 다시 가서 요리를 손님에게 갖다 줍니다. (콜백 함수를 실행)
  • 장점: 슈퍼 종업원 한 명이서 수만 명의 주문을 받아낼 수 있습니다. 대기 시간이 없기 때문입니다.

기술적 동작 원리

Node.js 내부에서는 이 과정을 처리하기 위해 다음과 같은 구조가 유기적으로 돌아가요.

  1. Call Stack (호출 스택 - 종업원):
    • 작성한 자바스크립트 코드가 실행되는 곳이에요.
    • Node.js는 싱글 스레드이므로 이 스택이 단 하나뿐입니다. 한 번에 하나의 함수만 실행할 수 있어요.
  2. Libuv (백그라운드 - 주방):
    • 오래 걸리는 작업(파일 읽기, DB 조회 등)이 들어오면, Call Stack은 이 작업을 Libuv라는 라이브러리에게 토스해요.
    • Libuv는 운영체제의 기능을 빌리거나 별도의 스레드 풀을 사용하여 이 무거운 작업들을 처리해다.
  3. Callback Queue (콜백 큐 - 대기열):
    • Libuv(주방)에서 작업이 끝나면, 그 결과와 함께 실행해야 할 함수(콜백 함수)를 대기열(Queue)에 줄 세워요.
  4. Event Loop (이벤트 루프 - 지배인):
    • "Call Stack이 비었나?"를 계속 감시해요.
    • Call Stack이 텅 비었다면, Callback Queue에 있는 함수를 하나씩 꺼내서 Call Stack으로 옮겨줘요.

예시를 들어볼게요

console.log('1. 주문 받음');

setTimeout(() => {
  console.log('2. 요리 완성 (오래 걸림)');
}, 3000); // 3초 뒤 실행

console.log('3. 다음 주문 받음');
  1. console.log('1...')이 Call Stack에 들어가고 즉시 실행돼요. (출력: 1. 주문 받음)
  2. setTimeout을 만남. 비동기적으로 백그라운드(Libuv)로 던져버리고 바로 다음 줄로 넘어기요.
  3. console.log('3...')이 Call Stack에 들어가고 즉시 실행돼요. (출력: 3. 다음 주문 받음)
  4. (3초 후) 백그라운드에서 3초가 지났음을 알리고, console.log('2...')Callback Queue에 넣음.
  5. Event Loop가 Call Stack이 비었음을 확인 후, Queue에 있던 콜백함수를 Call Stack으로 가져와요.
  6. 콜백 함수인 console.log(2...) 가 실행돼요. (출력: 2. 요리 완성)

이벤트 루프를 차단하지 마세요

이벤트 루프를 차단하지 마세요 한글번역
만약 위에 예시에서 setTimeout 함수에 콜백으로 들어간 함수가 연산이 오래 걸리는 작업이면 어떻게 될까요?

콜백 큐에 들어오는 순서대로 콜스택이 빌 때마다 투입되는 설계는 이상적으로 보이지만, 여러 번 말했듯이 Node.js는 싱글 스레드 이기 때문에, 메인 스레드에서 시간이 오래 걸리는 연산이 시작될 경우 다른 작업을 하지 못해요.

그러니 무거운 연산이 필요한 경우, 워커 스레드를 따로 만들어서 해결해야해요.

Node.js는 언제 좋을까?

  • 잘하는 것 (I/O 작업): 데이터를 주고받는 게 많은 서비스 (채팅, 스트리밍, ZEP 같은 실시간 서버, API 서버). 종업원이 기다리지 않고 미친 듯이 주문을 받으므로 효율이 좋아요.

  • 못하는 것 (CPU 작업): 머리를 엄청 써야 하는 작업 (복잡한 수학 계산, 이미지/비디오 인코딩, AI 학습).

    • 한 명밖에 없는 종업원(싱글 스레드)이 일을 하느라 다른 주문을 못 받기 때문이에요.
  • 이벤트 루프에 대해서 우테코 피터의 테코톡을 참고했어요

profile
할 땐 하고 놀 땐 노는 일일놀놀입니다.

0개의 댓글