NodeJS
NodeJS
What is NodeJS?
이벤트 기반, 논 블로킹 I/O, 싱글 스레드라는 특성을 가진 Node.js는 자바스크립트 언어 기반의 서버 사이드 플랫폼입니다. Node.js의 핵심은 Chrome V8 자바스크립트 엔진과 libuv 라이브러리를 기반으로 하는 점입니다. V8 엔진은 자바스크립트 코드를 빠르고 효율적으로 실행하며, libuv는 이벤트 기반, 논 블로킹 I/O 모델을 제공합니다.
Node.js의 이벤트 기반 아키텍처는 요청이 들어올 때마다 이벤트를 생성하고 특정 콜백 함수를 호출하는 방식으로 동작합니다. 이를 통해 복잡한 웹 애플리케이션도 가볍고 효율적으로 구동할 수 있습니다.
논 블로킹 I/O 모델 덕분에 파일, 네트워크 관련 작업이 이루어질 때 해당 작업이 완료될 때까지 기다리지 않고 계속 다음 작업을 처리합니다. 이를 통해 동시성(concurrency)을 높이고 전체 응답성을 향상할 수 있습니다.
마지막으로 Node.js는 싱글 스레드 기반으로 한 번에 하나의 작업만 수행합니다. 하지만 논 블로킹 I/O와 적절한 이벤트 루프 스케줄링을 통해 병렬성을 구현할 수 있습니다.
노드의 싱글 스레드 기반과 병렬성의 원리
노드JS는 싱글 스레드 기반이지만 비동기 처리 모델을 사용하여 병렬성을 구현할 수 있습니다.
가장 큰 특징은 논블로킹 I/O입니다. 파일 처리, 네트워크 통신과 같은 I/O 작업이 발생하면 해당 작업을 위한 스레드를 생성하지 않고 이벤트 루프를 사용하여 처리합니다.
I/O 작업이 완료되면 큐에 콜백 함수를 추가하고, 이벤트 루프는 큐의 콜백을 순차적으로 실행합니다. 이 과정에서 블로킹이 발생하지 않으므로 실질적으로 병렬 처리가 가능합니다. 또한 클러스터 모듈을 사용하면 멀티 코어 시스템에서 병렬성을 향상할 수 있습니다.
이벤트 루프 동작 방식
이벤트 루프(Event Loop)는 Node.js의 핵심 컨셉 중 하나로, 비동기 작업과 콜백을 처리하는 방식이다.
Node.js는 싱글 스레드 기반으로 동작하는데 이벤트 루프를 통해 병렬 처리가 가능하도록 구현됩니다.
작동 방식을 하나씩 살펴 봅시다.
1. Node.js는 이벤트 큐(Event Queue)를 가지고 있습니다.
2. 파일 I/O, 네트워크 I/O, 타이머 등의 작업이 완료되면 콜백 함수가 큐에 추가됩니다.
3. 이벤트 루프는 큐를 지속적으로 확인하면서 콜백을 하나씩 비동기적으로 실행합니다.
싱글 스레드의 고성능을 발휘하는 방법
노드 JS의 싱글 스레드 모델에서 고성능을 내기 위해서는 몇 가지 주요 전략이 있습니다.
첫째, 비동기 프로그래밍을 활용하는 것입니다. 파일 I/O, 네트워크 I/O, 데이터베이스 접속 등의 작업을 가능한 비동기로 처리합니다. 콜백이나 프로미스를 사용하여 비동기 로직을 깔끔하게 관리할 수 있습니다.
둘째, 스레드 풀을 도입하는 것입니다. CPU 집약적 작업을 위한 스레드를 미리 만들어 두고 작업 큐를 분배하는 방식입니다. NodeJS 기본 스레드가 블록 되지 않고 병렬 처리가 가능합니다.
셋째, 클러스터링을 활용하는 것입니다. 멀티코어 시스템에서 노드 프로세스를 여러 개 띄우고 로드 밸런싱을 처리할 수 있습니다. 단일 프로세스 대비 안정성과 성능 향상을 기대할 수 있습니다.
클러스터링과 로드 밸런싱
클러스터링(Clustering)이란 단일 노드 프로세스를 여러 개 띄우고, 로드 밸런싱을 통해 요청을 분산 처리하는 기술입니다. 단일 노드 프로세스에서는 싱글 스레드 기반으로 CPU 코어 1개만 사용하기 때문에 다중 코어 시스템의 자원을 낭비합니다. 클러스터링을 활용하면 모든 코어를 사용할 수 있습니다. 예를 들면 쿼드 코어 시스템에서 노드 프로세스를 4개 띄우면 각 프로세스가 하나의 코어에서 동작하게 됩니다. 로드 밸런서가 각 프로세스에 요청을 순차적으로 배분합니다. 이를 통해 CPU와 메모리 자원을 보다 효율적으로 사용할 수 있고, 싱글 프로세스 대비 안정성도 향상됩니다. 하나의 프로세스가 죽어도 나머지가 정상 동작하기 때문입니다. 다만 클러스터 간 공유되는 상태(세션, 캐시 등) 관리에 주의가 필요한데 일부 데이터를 다른 저장소에 별도 관리하는 식으로 개발해야 합니다.
Compiled 언어와 Interpreted 언어
컴파일 언어와 인터프리터 언어는 프로그램 실행 방식에서 차이가 발생합니다.
컴파일 언어(Compiled Language)는 소스 코드를 컴파일러를 통해 기계어로 번역한 후 실행하는 언어입니다. 대표적으로 C, C++, Go 언어가 있습니다. 컴파일 언어의 장점은 실행 속도가 빠르고 효율적이라는 것입니다. 하지만 개발 생산성은 낮고 유연성이 떨어집니다.
반면에 인터프리터 언어(Interpreted Language)는 소스 코드를 실행할 때 인터프리터가 줄 단위로 읽어가며 바로 실행하는 언어입니다. 대표적으로 Python, Ruby, JavaScript가 있습니다. 인터프리터 언어의 장점은 개발 생산성과 유연성이 뛰어나다는 것입니다. 하지만 실행 속도가 느리고 효율성이 컴파일 언어에 비해 낮습니다.
최근에는 JIT(Just-In-Time) 컴파일러를 결합한 인터프리터 언어들이 등장하였고 이는 실행 성능을 대폭 향상했습니다. JIT 컴파일러는 실행 중에 자주 사용되는 코드를 기계어로 번역해서 속도 저하를 줄입니다. 개발 생산성과 실행 성능을 모두 고려할 때 하이브리드 방식을 사용하는 언어가 각광받을 것으로 예상됩니다.
자바스크립트 하나만의 언어로 프론트엔드 및 백엔드를 모두 구현할 수 있는 풀스택 개발자가 될 수 있으며 이는 엄청난 개발 생산성을 향살 할 수 있으니 자바스크립트를 배웁시다.