backend/Node.js

Node.js 기본 개념 정리

lgvv 2023. 7. 16. 13:43

Node.js 기본 개념 정리

 

Node.js를 공부하면서 필요한 핵심 개념을 정리

 

(공식문서 링크)

https://nodejs.org/ko

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

 

Node.js란?

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

(Chrome's V8 JavaScript 엔진 위에서 동작하는 JavaScript 런타임 환경)

 

즉, 브라우저 밖에서도 자바스크립트를 실행할 수 있게 해주는 플랫폼

 

Node는 내부적으로 V8과 libuv를 함께 사용

  • V8: 오픈소스 자바스크립트 엔진
  • libuv: 비동기 I/O를 위한 라이브러리 (이벤트 기반, 논블로킹 I/O 모델 구현)

 

이벤트 기반(Event-Driven)

Node.js는 이벤트 중심으로 동작
클릭, 네트워크 요청 등 이벤트 발생 시 등록된 콜백 함수가 실행되는 구조

 

이벤트 기반에 대한 예시 코드

function first() { 
  second();
  console.log('first');
}

function second() { 
  third();
  console.log('second');
}

function third() { 
  console.log('third');
}

first();

// 출력
third
second
first

 

자바스크립트의 실행순서!

 

자바스크립트는 호출 스택(Call Stack) 을 기반으로 위에서부터 아래로 실행
즉, third()가 먼저 실행되고, 이후 second(), first() 순서로 호출 스택이 비워짐.

 

  • 호출 스택(Call Stack): 실행 중인 함수들이 쌓이는 스택
  • 백그라운드(Background): setTimeout, 네트워크 요청 등 대기 중인 작업 영역
  • 태스크 큐(Task Queue): 실행 대기 중인 콜백 함수들이 순서대로 줄 서 있는 큐

 


anonymous 함수는 처음 실행 시의 전역 컨텍스트를 의미.

아래는 특정 밀리초 이후에 코드를 실행하는 setTimeout 코드

function run() { 
	console.log('3초 후 실행');
}

console.log('시작');
setTimeout(run, 3000);
console.log('끝');

// 출력결과
시작
끝
3초 후 실행



이벤트 루프는 호출 스택이 비워졌을 때 태스크 큐에 있는 콜백을 스택으로 옮겨 실행
따라서 setTimeout이 3초 뒤에 완료되더라도, 호출 스택이 비어 있어야 콜백이 실제로 실행


즉, setTimeout의 지연 시간은 “정확한 실행 시간”을 보장하지 않음.

 

  • 블로킹(Blocking): 이전 작업이 끝날 때까지 다음 작업이 대기
  • 논블로킹(Non-Blocking): 이전 작업의 완료를 기다리지 않고 바로 다음 코드 실행

 

블로킹 예시

function longTask() {
  console.log('작업 끝');
}

console.log('시작');
longTask();
console.log('다음 작업');

// 시작
// 작업 끝
// 다음 작업

 

 

논블로킹 예시

function longTask() {
  console.log('작업 끝');
}

console.log('시작');
setTimeout(longTask, 0);
console.log('다음 작업');

// 시작
// 다음 작업
// 작업 끝

 

Node.js는 비동기 I/O 기반의 논블로킹 모델을 사용하기 때문에, I/O가 많은 서버 환경에서 효율적으로 동작.

 

 

전체적으로 한번 정리

  • 이벤트 루프(Event Loop): 이벤트 발생 시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행 순서를 결정하는 역할을 담당.
    • 노드가 종료될 때까지 이벤트 처리를 위한 작업을 반복하므로 루프라고 부림
  • 백그라운드(Background): setTimeout 같은 타이머나 이벤트 리스너들이 대기하는 곳.
    • 자바스크립트가 아닌 다른 언어로 작성된 프로그램이라고 봐도 무방하며, 여러 작업이 동시에 실행될 수 있음.
  •  태스트 큐(Task Queue): 이벤트 발생 후 백그라운드에서는 태스크 큐로 타이머나 이벤트 리스너의 콜백 함수로 보냄.
    • 정해진 순서대로 콜백들이 줄을 서 있으므로 콜백 큐라고도 불림.
    • 콜백은 보통 안료된 순서대로 줄을 서 있지만, 특정한 경우 순서가 바뀌기도 함.

 

앞에 위치할수록 스택에 먼저 들어왔다고 생각할 수 있음.

예시)

호출스택: A - B - C인 경우에는 A가 먼저 들어오고 C가 제일 나중에 스택에 쌓임

 

 

만약 호출 스택에 함수가 너무 많이 들어 있다면 3초가 지난 후에서 run 함수가 실행되지 않을 수 있음.

이벤트 루프는 호출 스택이 비어 있을 때만 태스크 큐에 있는 run 함수를 호출 스택으로 가져오기 때문

이러한 이유로 setTimeout의 시간이 정확하지 않을 수도 있는 이유가 됨.

 

// 1. 이벤트 루프1
 - 호출스택: anonymous - setTimeout()
 - 백그라운드: 타이머 run 3초
 - 태스크 큐: run

1-1) 호출스택에 쌓임
1-2) setTimeout 실행 시 콜백 run은 콜백 백그라운드로 보냄
1-3) 백그라운드에서 3초 후 태스크 큐로 보냄

// 2. 이벤트 루프2
 - 호출스택:
 - 백그라운드:
 - 태스크 큐: run
 
2-1) 호출 스택 실행이 끝나 비워지면
2-2) 이벤트 루프가 태스크 큐의 콜백을 호출 스택으로 올림

// 3. 이벤트 루프3
 - 호출스택: run()
 - 백그라운드:
 - 태스크 큐:
 
3-1) run이 호출 스택에서 실행되고 제거됨
3-2) 이벤트 루프는 태스크 큐에 콜백이 들어올 때까지 대기

 

 

 

노드의 싱글 스레드 구조

Node.js는 흔히 싱글 스레드라고 불리지만, 실제로는 내부적으로 여러 스레드를 사용

  • 프로세스: 운영체제에서 실행되는 독립적인 프로그램 단위
    • 프로세스 간 메모리 등 자원을 공유하지 않음.
  • 스레드: 프로세스 내에서 실행되는 작업 흐름 단위
    • 일반적으로 부모 자원을 온전히 공유하지 않음.
    • vfork() 등 공유하게 만드는 기법도 존재하긴 함

 

Node.js는 하나의 메인 스레드로 자바스크립트 코드를 실행.

libuv의 스레드 풀을 통해 내부적으로 병렬 작업을 처리

 

 

즉, 노드는 엄밀히 말하면 싱글스레드로 동작하지는 않음.

  • 1. 노드 실행시 프로세스가 하나 생성되고 그 프로세스에서 스레드들을 생성.
  • 2. 이 때 내부적으로 스레드를 여러개 생성. 
  • 3. 다만, 우리가 직접 제어할 스레드는 하나뿐.(그래서 흔히 싱글스레드로 여겨짐.)

블로킹이 심하게 일어나는 작업이 아니라면 하나의 스레드로도 충분히 가능.

 

 

멀티스레드가 동작하는 경우

  1. 스레드 풀 (Thread Pool)
    • 암호화, 파일 입출력, 압축 등 특정 작업을 내부적으로 병렬 처리
  2. 워커 스레드 (Worker Threads)
    • Node.js 12 이상부터 도입된 기능
    • CPU 연산이 많은 경우 직접 여러 스레드를 생성해 사용 가능

 

 

서버로서의 Node.js

Node.js는 실시간 통신과 I/O 중심의 작업에 강점을 보임.

  • 실시간 채팅 서비스
  • 주식/코인 실시간 차트
  • JSON 기반의 API 서버


Node.js의 장점

  1. 적은 리소스로 높은 동시성 처리
  2. I/O 중심의 서버에 최적화
  3. 코드가 간결하고 유지보수 용이
  4. 웹 서버 내장 (추가 설정 불필요)
  5. JavaScript 사용으로 프론트엔드와 언어 통일
  6. JSON과의 높은 호환성


Node.js의 단점

  1. CPU 연산이 많은 경우 비효율적
  2. 싱글 스레드 특성상 한 작업이 전체를 블로킹할 수 있음
  3. 서버가 커질수록 관리 복잡도 증가
  4. 중간 수준의 성능 (CPU 연산과 I/O 모두 완벽하지 않음)