Node.js는 브라우저 내부에 갇혀 있던 JavaScript를 서버사이드(Server-side) 환경으로 끌어낸 혁신적인 런타임입니다. 구글의 초고속 V8 엔진과 비동기 처리를 위한 이벤트 기반의 논블로킹(Non-blocking) I/O 아키텍처를 결합하여, 가볍고 효율적이면서도 압도적인 성능을 내는 네트워크 애플리케이션을 구축할 수 있습니다.
Node.js의 심장은 구글 크롬 브라우저를 위해 개발된 V8 JavaScript 엔진입니다. C++로 작성된 이 엔진은 코드를 실행할 때마다 한 줄씩 해석하는 인터프리터(Interpreter) 방식의 한계를 극복하기 위해, 실행 직전에 소스 코드를 기계어(Machine Code)로 즉시 번역해버리는 JIT(Just-In-Time) 컴파일러를 탑재하여 C, C++에 버금가는 놀라운 실행 속도를 제공합니다.
기존의 서버 언어(PHP, Java 등)는 DB를 조회하거나 파일을 읽을 때 응답이 올 때까지 스레드(Thread)가 멈춰서 기다리는 블로킹(Blocking) 모델을 사용합니다. 하지만 Node.js는 이런 무거운 입출력(I/O) 작업을 던져놓고 멈춤 없이 즉시 다음 코드를 실행하러 가는 논블로킹(Non-blocking) 모델을 채택하여 서버 자원을 극도로 효율적으로 사용합니다.
| 구분 | 코드 및 서버 동작 방식 | 실생활 비유 (카페 주문) |
|---|---|---|
| 블로킹 (Blocking) | 1번 작업이 끝날 때까지 CPU가 아무 일도 못하고 2번 작업을 대기시킴. (동기) | 직원이 앞사람의 커피를 다 만들어 건네줄 때까지, 뒷사람이 주문도 못하고 줄 서서 멍하니 대기함. |
| 논블로킹 (Non-blocking) | 1번 작업을 백그라운드에 던지고 즉시 2번 작업 실행. 완료되면 콜백으로 알림. (비동기) | 직원이 주문만 연속으로 받고 손님에게 진동벨을 줌. 커피가 나오는 대로(작업 완료) 진동벨을 울림. |
"자바스크립트는 싱글 스레드인데 어떻게 동시에 수많은 비동기 작업을 처리하나요?" 라는 질문에 대한 해답이 바로 이벤트 루프(Event Loop)와 libuv 라이브러리입니다. 무거운 작업은 백그라운드의 워커 스레드 풀(Thread Pool)이나 OS 커널로 넘기고, 메인 스레드(이벤트 루프)는 오직 작업 완료 알림(콜백)만 부지런히 큐(Queue)에서 꺼내어 실행하기 때문에 단 1개의 스레드만으로 수만 개의 연결을 처리할 수 있습니다.
위의 터미널 목업 로그를 보면 Node.js의 비동기적 특성을 명확히 알 수 있습니다. 코드의 작성 순서는 1 → 3 → 2 번이지만, 실제 콘솔 출력 결과는 1 → 2 → 3 번 순서로 찍히는 것을 확인할 수 있습니다. 무거운 I/O 작업(파일 읽기)을 백그라운드로 넘겨둔 채 메인 스레드는 즉시 2번 로직을 처리하고, 추후 파일 읽기가 완료되면 이벤트 루프가 3번 콜백을 호출해 주는 완벽한 논블로킹(Non-blocking) 흐름을 보여줍니다.