본문 바로가기
Frontend/Javascript

Node.js란(등장배경/내부구조/작동방식)

by 디스코비스킷 2024. 7. 23.
반응형

Nodejs의 등장배경

Nodejs란?

자바스크립트를 실행시키는 런타임 환경

자바스크립트는 브라우저 종속 언어였다. 브라우저 밖에서 실행하려는 몇가지 시도가 있었는데, 이렇게 실행된 js의 속도가 너무나 느려서 사용되진 못함 구글에서 V8엔진을 탑재한 크롬브라우저가 나오면서 바뀜.

크롬브라우저는 더 빨리 js를 실행할 수있게됨 V8엔진코드도 오픈소스로 공개됨

이때 구글 개발자가 Node프로젝트를 시작하게됨. 이게 Nodejs로 탄생하게됨

비동기 이벤트 주도 Javascript 런타임으로써 Nodejs는 확장성 있는 네트워크 어플리케이션을 만들 수 있도록 설계되었다.

“비동기 이벤트 주도”

자바스크립트에서 비동기를 처리하는 방법: Async, await, Promise, callback…

이벤트 주도 방식이란?

Node.js에서 이벤트 주도 방식(Event-Driven Programming)은 비동기 프로그래밍 모델로, 시스템이 발생하는 이벤트(예: 사용자 입력, 메시지 도착, 타이머 종료 등)를 기반으로 동작하는 프로그래밍 패러다임이다. Node.js의 핵심 개념 중 하나로, 특히 서버 애플리케이션을 작성할 때 매우 유용하다.

이벤트 주도 방식의 핵심 개념

  1. 이벤트 루프(Event Loop):
    • Node.js의 런타임이 제공하는 비동기 운영을 지원하는 메커니즘이다.
    • 이벤트 루프는 호출 스택(Call Stack)과 이벤트 큐(Event Queue)를 관리하며, 비동기 작업이 완료될 때마다 콜백 함수를 호출한다.
  2. 이벤트:
    • 이벤트는 특정 상황이 발생했음을 나타내는 신호다. 예를 들어, HTTP 요청이 도착하거나 파일 읽기가 완료된 경우 등이 이벤트가 될 수 있다.
  3. 이벤트 핸들러(Event Handler):
    • 특정 이벤트가 발생했을 때 실행되는 함수다. 이벤트 리스너(Event Listener)라고도 한다.
  4. 이벤트 발행자(Event Emitter):
    • 이벤트를 발생시키는 객체다. Node.js에서 대부분의 내장 모듈은 이벤트 발행자로 동작하며, EventEmitter 클래스를 사용하여 커스텀 이벤트 발행자를 만들 수도 있다.

이벤트 주도 방식의 동작 원리

  1. 이벤트 등록:
    • 이벤트 발행자에 이벤트 핸들러를 등록한다. 예를 들어, HTTP 서버 객체에 클라이언트 요청 이벤트를 등록할 수 있다.
    const EventEmitter = require('events');
    const myEmitter = new EventEmitter();
    
    myEmitter.on('event', () => {
      console.log('An event occurred!');
    });
    
  2. 이벤트 발생:
    • 특정 조건이 만족되면 이벤트가 발생하고, 이벤트 루프는 해당 이벤트 핸들러를 실행한다.
    myEmitter.emit('event');
    

예제 코드

아래는 간단한 HTTP 서버를 만드는 예제다. 클라이언트 요청이 들어올 때마다 'request' 이벤트가 발생하고, 등록된 핸들러가 실행된다.

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\\n');
});

server.on('request', (req, res) => {
  console.log(`Request received: ${req.url}`);
});

server.listen(3000, '127.0.0.1', () => {
  console.log('Server running at <http://127.0.0.1:3000/>');
});

장점

  1. 높은 확장성:
    • 비동기 I/O와 이벤트 기반 모델을 통해 많은 수의 동시 접속을 효율적으로 처리할 수 있다.
  2. 간단한 코드 구조:
    • 콜백 함수를 사용해 비동기 작업을 쉽게 관리할 수 있으며, 코드의 흐름이 명확해진다.

단점

  1. 복잡한 에러 처리:
    • 비동기 코드에서 발생하는 에러를 적절히 처리하지 않으면 예기치 않은 버그가 발생할 수 있다.
  2. 콜백 헬:
    • 중첩된 콜백 함수들이 많아지면 코드가 읽기 어렵고 유지보수하기 어려워질 수 있다. 이를 해결하기 위해 Promises나 async/await가 사용된다.

이벤트 주도 방식은 Node.js의 비동기 처리 능력을 극대화할 수 있는 강력한 방법이다. 이를 잘 활용하면 고성능의 확장 가능한 애플리케이션을 작성할 수 있다.

이벤트 주도 방식 vs 쓰레드 기반 동시성 모델

항목 쓰레드 기반 동시성 모델 이벤트 주도 방식

기본 개념 각 작업이 독립된 쓰레드에서 실행 이벤트 루프와 비동기 콜백을 사용
운영체제 역할 운영체제가 쓰레드 스케줄링 및 관리 주로 단일 스레드에서 이벤트 루프 관리
오버헤드 쓰레드 생성, 관리 및 문맥 전환 비용 큼 문맥 전환 오버헤드 없음
동기화 문제 공유 자원 접근 시 동기화 필요 단일 스레드에서 실행되어 동기화 문제 없음
복잡성 복잡한 동기화 및 데드락 위험 콜백 지옥(Callback Hell) 발생 가능
확장성 멀티코어 활용으로 병렬 처리 가능 많은 동시 연결을 효율적으로 처리 가능
직관성 동기식 코드와 유사하여 이해하기 쉬움 비동기 코드로 복잡해질 수 있음
에러 처리 상대적으로 간단 복잡한 에러 처리
적용 분야 CPU 집약적인 작업 I/O 집약적인 작업
예제 Python, Java의 멀티쓰레딩 Node.js의 비동기 I/O

쓰레드 기반 동시성 모델은 여러개의 쓰레드가 동시에 진행하며, 교착상태(데드락)가 발생할 수 있음. Nodejs는 멀티쓰레드 보다 싱글 쓰레드를 효율적으로 사용할 수 있는 이벤트 루프를 선택했다.

Nodejs의 실행 방식

위에서부터 차례대로 실행, 특정시간을 할당해서 그시간만큼 작업을 처리하는 라운드 로빈 방식

nodejs event loop vs brower event loop

근본적으로 차이는 별로 없고..

Process.nextTick 이란 api가 있음. 특정단계는 할당된 시간에 구애받지 않음 → 사용자 주의 필요

항목 Node.js 이벤트 루프 브라우저 이벤트 루프

환경 서버 사이드 환경 클라이언트 사이드 환경
기본 목적 서버에서 비동기 I/O 작업 처리 사용자 인터페이스 이벤트 및 비동기 작업 처리
기반 엔진 V8 JavaScript 엔진 V8 (Chrome), SpiderMonkey (Firefox), JavaScriptCore (Safari) 등
핵심 모듈 libuv 브라우저 자체 제공 (DOM API 등)
타이머 관리 Node.js의 setTimeout, setInterval 브라우저의 setTimeout, setInterval
I/O 처리 비동기 I/O 작업, 파일 시스템 접근, 네트워크 요청 처리 사용자 이벤트, 네트워크 요청, DOM 조작
태스크 큐 (Task Queue) 마이크로태스크 큐와 매크로태스크 큐 구분 마이크로태스크 큐와 매크로태스크 큐 구분
마이크로태스크 process.nextTick, Promise Promise, MutationObserver
매크로태스크 I/O 작업, 타이머 콜백, setImmediate 사용자 이벤트, 타이머 콜백, 네트워크 이벤트
렌더링 없음 렌더링 엔진과 협력하여 UI 업데이트
추가 기능 클러스터링, 스트리밍, 네트워크 프로토콜 지원 브라우저 API, DOM 조작, CSSOM 처리

주요 차이점 설명

  1. 환경:
    • Node.js 이벤트 루프는 서버 사이드 환경에서 실행되며, 주로 서버에서 비동기 I/O 작업을 처리하는 데 중점을 둔다.
    • 브라우저 이벤트 루프는 클라이언트 사이드 환경에서 실행되며, 사용자 인터페이스 이벤트 및 비동기 작업 처리를 주로 한다.
  2. 기반 엔진 및 핵심 모듈:
    • Node.js는 V8 JavaScript 엔진을 기반으로 하고, libuv를 통해 이벤트 루프를 구현한다.
    • 브라우저는 다양한 JavaScript 엔진(V8, SpiderMonkey, JavaScriptCore 등)을 사용하며, 브라우저 자체에서 이벤트 루프를 제공한다.
  3. I/O 처리 및 타이머 관리:
    • Node.js 이벤트 루프는 파일 시스템 접근, 네트워크 요청 등 서버 측 비동기 I/O 작업을 효율적으로 처리한다.
    • 브라우저 이벤트 루프는 사용자 이벤트, 네트워크 요청, DOM 조작 등 클라이언트 측 비동기 작업을 처리한다.
  4. 렌더링:
    • Node.js는 서버 사이드 환경으로, 렌더링 작업이 필요하지 않다.
    • 브라우저는 렌더링 엔진과 협력하여 UI 업데이트를 수행한다.
  5. 추가 기능:
    • Node.js는 클러스터링, 스트리밍, 네트워크 프로토콜 등의 추가 기능을 제공한다.
    • 브라우저는 브라우저 API, DOM 조작, CSSOM 처리 등 다양한 클라이언트 사이드 기능을 제공한다.

두 이벤트 루프는 비동기 작업을 처리하는 공통적인 목적을 가지고 있지만, 각 환경의 요구사항에 맞춰 설계되었다. Node.js 이벤트 루프는 서버 측의 고성능 비동기 I/O 처리를, 브라우저 이벤트 루프는 사용자 인터페이스의 부드러운 동작을 목표로 한다.

논 블로킹 I/O 모델

Node.js에서 I/O를 직접 수행하는 함수는 거의 없으므로 프로세스는 블로킹되지 않는다. 그러므로 Node.js에서는 확장성 있는 시스템을 개발하는 게 아주 자연스럽다.

자바스크립트는 싱글쓰레드 언어이므로 블로킹모델을 사용할 수 없음!

블로킹모델 문제점

블로킹 모델에서는 작업이 완료될 때까지 현재 쓰레드가 멈추게 된다. 이를 자바스크립트 환경에 적용했을 때 발생하는 문제점은 다음과 같다:

  • 사용자 경험 저하:
    • 브라우저 환경에서 자바스크립트가 블로킹 작업을 수행하면, 해당 작업이 완료될 때까지 사용자가 페이지와 상호작용할 수 없다. 이는 페이지가 "멈추는" 경험을 하게 만들며, 사용자의 인터페이스가 응답하지 않게 된다.
  • 전체 애플리케이션 정지:
    • 자바스크립트는 싱글 쓰레드 언어이므로, 하나의 작업이 블로킹되면 다른 모든 작업이 중단된다. 이는 서버 측에서도 문제가 될 수 있으며, Node.js 서버의 경우 모든 클라이언트 요청이 중단되는 상황이 발생할 수 있다.
  • 성능 저하:
    • 블로킹 작업이 길어질수록 전체 애플리케이션의 응답성이 저하된다. 이는 특히 고성능, 고확장성 서버가 요구되는 환경에서 큰 단점이 된다.

블로킹 코드 (문제점 발생)

javascript코드 복사
function sleep(milliseconds) {
    const start = Date.now();
    while (Date.now() - start < milliseconds) {
        // 아무것도 하지 않음 (블로킹)
    }
}

console.log("Start");
sleep(5000); // 5초 동안 블로킹
console.log("End");

위 코드는 5초 동안 CPU를 점유하며 다른 작업을 차단한다. 브라우저에서는 이 시간 동안 페이지가 멈추고, Node.js 서버에서는 모든 요청이 대기 상태가 된다.

비동기 코드 (문제 해결)

javascript코드 복사
console.log("Start");

setTimeout(() => {
    console.log("End");
}, 5000); // 5초 후에 콜백 실행 (비동기)

console.log("Continuing execution...");

위 코드는 setTimeout을 사용하여 비동기적으로 작업을 처리한다. 브라우저에서는 페이지가 계속 응답하고, Node.js 서버에서는 다른 요청을 처리할 수 있게 된다.

자바스크립트의 비동기 패러다임

자바스크립트는 비동기 프로그래밍을 위해 콜백, 프라미스(Promises), 그리고 async/await 같은 패턴을 제공한다. 이를 통해 싱글 쓰레드 환경에서도 블로킹 없이 비동기 작업을 효율적으로 처리할 수 있다.

노드의 내부 구조

+-------------------------------------------------+
|                     Node.js                     |
| +---------------------------------------------+ |
| |                V8 JavaScript Engine         | |
| |                                             | |
| +---------------------------------------------+ |
| +---------------------------------------------+ |
| |                     libuv                   | |
| |  +----------------+  +--------------------+ | |
| |  | 이벤트 루프    |  | 비동기 I/O          | | |
| |  +----------------+  +--------------------+ | |
| +---------------------------------------------+ |
| +---------------------------------------------+ |
| |                C++ 바인딩                   | |
| +---------------------------------------------+ |
| +---------------------------------------------+ |
| |              Node.js 표준 라이브러리         | |
| +---------------------------------------------+ |
+-------------------------------------------------+

libuv에 이벤트루프가 있음. libuv는 다양한 작업을 수행하는 C기반의 라이브러리다. 이벤트루프에 던져진 비동기 작업들은 이벤트 루프 내부가 아닌 system kernel에서 수행된다.

Node.js의 내부 구조는 다음과 같은 주요 구성 요소로 이루어져 있다:

  1. V8 JavaScript 엔진:
    • 구글 크롬에서 사용하는 고성능 JavaScript 엔진이다.
    • JavaScript 코드를 머신 코드로 변환하여 빠르게 실행한다.
  2. libuv:
    • 비동기 I/O를 처리하는 라이브러리다.
    • 이벤트 루프, 파일 시스템, 네트워크 작업 등을 관리하며, 크로스 플랫폼 비동기 I/O 기능을 제공한다.
  3. C++ 바인딩:
    • Node.js의 많은 핵심 모듈은 C++로 작성되어 있으며, V8과 libuv와 상호작용한다.
    • 고성능의 네이티브 코드와 JavaScript 코드 간의 인터페이스를 제공한다.
  4. 이벤트 루프:
    • Node.js의 핵심 구성 요소로, 비동기 작업을 관리하고 실행하는 역할을 한다.
    • 다양한 큐를 사용하여 작업을 관리하며, 비동기 I/O 작업, 타이머, process.nextTick, Promise 등을 처리한다.
  5. Node.js 표준 라이브러리:
    • 파일 시스템, 네트워크, 스트림, 버퍼, 암호화 등 다양한 기능을 제공하는 내장 모듈 모음이다.
    • 개발자가 다양한 기능을 쉽게 사용할 수 있도록 API를 제공한다.

각 구성 요소의 역할

  1. V8 JavaScript 엔진:
    • JavaScript 코드를 컴파일하고 실행하는 역할을 한다.
    • 성능을 극대화하기 위해 최적화된 JIT(Just-In-Time) 컴파일을 사용한다.
  2. libuv:
    • 이벤트 루프와 비동기 I/O 작업을 관리하는 역할을 한다.
    • 운영 체제의 기능을 추상화하여 크로스 플랫폼 지원을 가능하게 한다.
    • 다음과 같은 기능을 제공한다:
      • 파일 시스템 작업 (읽기, 쓰기 등)
      • 네트워크 작업 (HTTP, TCP, UDP 등)
      • 타이머 (setTimeout, setInterval)
      • DNS 조회
      • 이벤트 루프 관리
  3. C++ 바인딩:
    • 고성능 네이티브 코드를 Node.js와 통합하는 역할을 한다.
    • V8과 libuv와의 상호작용을 위한 인터페이스를 제공한다.
  4. 이벤트 루프:
    • 비동기 작업의 실행 순서를 관리하는 역할을 한다.
    • 이벤트 루프는 다음과 같은 단계로 구성된다:
      • Timers: setTimeout과 setInterval의 콜백을 실행한다.
      • Pending Callbacks: 일부 I/O 작업의 콜백을 실행한다.
      • Idle, Prepare: 내부적으로 사용된다.
      • Poll: 새로운 I/O 이벤트를 가져오고, I/O 관련 콜백을 실행한다.
      • Check: setImmediate 콜백을 실행한다.
      • Close Callbacks: 닫힌 소켓 등의 콜백을 실행한다.
  5. Node.js 표준 라이브러리:
    • 개발자가 쉽게 사용할 수 있는 다양한 모듈을 제공한다.
    • 파일 시스템, 네트워크, 스트림, 버퍼, 암호화 등의 기능을 포함한다.
    • 이러한 모듈은 대부분 비동기로 작동하여 이벤트 루프와 함께 원활하게 동작한다.

Node.js는 이러한 구성 요소들이 유기적으로 결합되어 비동기 I/O를 효율적으로 처리하고, 고성능의 서버 사이드 애플리케이션을 개발할 수 있도록 한다.

libuv는 Node.js의 핵심 라이브러리로, 비동기 I/O 작업을 관리하고 처리하는 역할을 한다. libuv의 이벤트 루프는 다양한 작업을 관리하지만, 실제로 비동기 작업의 많은 부분은 시스템 커널에서 수행된다. 이를 이해하기 위해 libuv의 이벤트 루프와 시스템 커널 간의 상호작용을 자세히 설명하겠다.

libuv와 이벤트 루프

libuv의 이벤트 루프는 Node.js의 비동기 작업을 관리하는 중심 역할을 한다. 이벤트 루프는 다양한 비동기 작업을 큐에 넣고, 순차적으로 처리하는 방식으로 동작한다. 이벤트 루프가 처리하는 주요 작업에는 파일 시스템 I/O, 네트워크 I/O, 타이머, DNS 조회 등이 포함된다.

시스템 커널의 역할

비동기 작업의 많은 부분은 libuv 이벤트 루프 내부에서 직접 수행되지 않고, 시스템 커널에 의해 처리된다. 시스템 커널은 운영체제의 핵심 부분으로, 하드웨어와 직접 상호작용하며 다양한 저수준 작업을 처리한다.

비동기 작업의 흐름

  1. 이벤트 루프에 작업 등록:
    • 자바스크립트 코드에서 비동기 작업을 요청하면, libuv는 해당 작업을 이벤트 루프의 작업 큐에 등록한다.
    • 예를 들어, 파일 읽기 요청을 할 때 fs.readFile 호출은 libuv를 통해 이벤트 루프에 작업을 등록한다.
  2. 시스템 커널로 작업 위임:
    • libuv는 비동기 작업을 처리하기 위해 시스템 커널에 해당 작업을 요청한다.
    • 시스템 커널은 파일 시스템 작업, 네트워크 I/O 등의 작업을 실제로 수행한다.
    • 이 과정에서 커널은 비동기 작업의 완료 여부를 비동기적으로 이벤트 루프에 통지한다.
  3. 이벤트 루프에서 콜백 처리:
    • 시스템 커널이 작업을 완료하면, libuv의 이벤트 루프는 해당 작업에 대한 콜백을 실행한다.
    • 이 콜백 함수는 자바스크립트 코드에서 정의한 작업 완료 후의 처리를 담당한다.

예제 흐름: 파일 읽기

  1. 비동기 파일 읽기 요청:
  2. const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log(data); });
  3. libuv가 요청을 시스템 커널에 전달:
    • fs.readFile 호출 시 libuv는 해당 파일 읽기 작업을 시스템 커널에 요청한다.
    • 시스템 커널은 파일 읽기 작업을 시작하고, 완료될 때까지 다른 작업을 계속 처리한다.
  4. 시스템 커널에서 작업 완료:
    • 시스템 커널이 파일 읽기를 완료하면, 이 정보를 libuv에 통지한다.
  5. libuv 이벤트 루프가 콜백 실행:
    • 이벤트 루프는 파일 읽기 작업이 완료된 것을 감지하고, 등록된 콜백 함수를 실행한다.
    • 콜백 함수는 읽어온 파일 내용을 출력하거나 에러를 처리한다.

결론

libuv는 Node.js의 이벤트 루프를 통해 비동기 작업을 관리하지만, 실제 작업의 많은 부분은 시스템 커널에서 수행된다. 이는 libuv가 고성능, 비동기 I/O를 효율적으로 처리할 수 있는 이유 중 하나다. 이벤트 루프는 이러한 작업의 상태를 모니터링하고, 작업이 완료되면 적절한 콜백을 실행하여 비동기 프로그래밍 모델을 구현한다.

정리

  • Node.js는 V8엔진의 등장과 함께 개발된 자바스크립트 런타임 환경
  • 비동기 이벤트 주도, 논-블로킹으로 효율적이고, 확장성있는 네트워크 앱을 만들 수 있도록 설계
  • libuv를 이용해 비동기 작업을 시스템 커널에 위임하며 동작

    Nodejs의 등장배경

    Nodejs란?자바스크립트는 브라우저 종속 언어였다. 브라우저 밖에서 실행하려는 몇가지 시도가 있었는데, 이렇게 실행된 js의 속도가 너무나 느려서 사용되진 못함 구글에서 V8엔진을 탑재한 크롬브라우저가 나오면서 바뀜.이때 구글 개발자가 Node프로젝트를 시작하게됨. 이게 Nodejs로 탄생하게됨“비동기 이벤트 주도”이벤트 주도 방식이란?이벤트 주도 방식의 핵심 개념
    1. 이벤트 루프(Event Loop):
      • Node.js의 런타임이 제공하는 비동기 운영을 지원하는 메커니즘이다.
      • 이벤트 루프는 호출 스택(Call Stack)과 이벤트 큐(Event Queue)를 관리하며, 비동기 작업이 완료될 때마다 콜백 함수를 호출한다.
    2. 이벤트:
      • 이벤트는 특정 상황이 발생했음을 나타내는 신호다. 예를 들어, HTTP 요청이 도착하거나 파일 읽기가 완료된 경우 등이 이벤트가 될 수 있다.
    3. 이벤트 핸들러(Event Handler):
      • 특정 이벤트가 발생했을 때 실행되는 함수다. 이벤트 리스너(Event Listener)라고도 한다.
    4. 이벤트 발행자(Event Emitter):
      • 이벤트를 발생시키는 객체다. Node.js에서 대부분의 내장 모듈은 이벤트 발행자로 동작하며, EventEmitter 클래스를 사용하여 커스텀 이벤트 발행자를 만들 수도 있다.
    이벤트 주도 방식의 동작 원리
    1. 이벤트 등록:
      • 이벤트 발행자에 이벤트 핸들러를 등록한다. 예를 들어, HTTP 서버 객체에 클라이언트 요청 이벤트를 등록할 수 있다.
      const EventEmitter = require('events');
      const myEmitter = new EventEmitter();
      
      myEmitter.on('event', () => {
        console.log('An event occurred!');
      });
      
    2. 이벤트 발생:
      • 특정 조건이 만족되면 이벤트가 발생하고, 이벤트 루프는 해당 이벤트 핸들러를 실행한다.
      myEmitter.emit('event');
      
    예제 코드
    const http = require('http');
    
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello World\\n');
    });
    
    server.on('request', (req, res) => {
      console.log(`Request received: ${req.url}`);
    });
    
    server.listen(3000, '127.0.0.1', () => {
      console.log('Server running at <http://127.0.0.1:3000/>');
    });
    
    장점
    1. 높은 확장성:
      • 비동기 I/O와 이벤트 기반 모델을 통해 많은 수의 동시 접속을 효율적으로 처리할 수 있다.
    2. 간단한 코드 구조:
      • 콜백 함수를 사용해 비동기 작업을 쉽게 관리할 수 있으며, 코드의 흐름이 명확해진다.
    단점
    1. 복잡한 에러 처리:
      • 비동기 코드에서 발생하는 에러를 적절히 처리하지 않으면 예기치 않은 버그가 발생할 수 있다.
    2. 콜백 헬:
      • 중첩된 콜백 함수들이 많아지면 코드가 읽기 어렵고 유지보수하기 어려워질 수 있다. 이를 해결하기 위해 Promises나 async/await가 사용된다.
    이벤트 주도 방식은 Node.js의 비동기 처리 능력을 극대화할 수 있는 강력한 방법이다. 이를 잘 활용하면 고성능의 확장 가능한 애플리케이션을 작성할 수 있다.항목 쓰레드 기반 동시성 모델 이벤트 주도 방식
    기본 개념 각 작업이 독립된 쓰레드에서 실행 이벤트 루프와 비동기 콜백을 사용
    운영체제 역할 운영체제가 쓰레드 스케줄링 및 관리 주로 단일 스레드에서 이벤트 루프 관리
    오버헤드 쓰레드 생성, 관리 및 문맥 전환 비용 큼 문맥 전환 오버헤드 없음
    동기화 문제 공유 자원 접근 시 동기화 필요 단일 스레드에서 실행되어 동기화 문제 없음
    복잡성 복잡한 동기화 및 데드락 위험 콜백 지옥(Callback Hell) 발생 가능
    확장성 멀티코어 활용으로 병렬 처리 가능 많은 동시 연결을 효율적으로 처리 가능
    직관성 동기식 코드와 유사하여 이해하기 쉬움 비동기 코드로 복잡해질 수 있음
    에러 처리 상대적으로 간단 복잡한 에러 처리
    적용 분야 CPU 집약적인 작업 I/O 집약적인 작업
    예제 Python, Java의 멀티쓰레딩 Node.js의 비동기 I/O
    쓰레드 기반 동시성 모델은 여러개의 쓰레드가 동시에 진행하며, 교착상태(데드락)가 발생할 수 있음. Nodejs는 멀티쓰레드 보다 싱글 쓰레드를 효율적으로 사용할 수 있는 이벤트 루프를 선택했다.Process.nextTick 이란 api가 있음. 특정단계는 할당된 시간에 구애받지 않음 → 사용자 주의 필요항목 Node.js 이벤트 루프 브라우저 이벤트 루프
    환경 서버 사이드 환경 클라이언트 사이드 환경
    기본 목적 서버에서 비동기 I/O 작업 처리 사용자 인터페이스 이벤트 및 비동기 작업 처리
    기반 엔진 V8 JavaScript 엔진 V8 (Chrome), SpiderMonkey (Firefox), JavaScriptCore (Safari) 등
    핵심 모듈 libuv 브라우저 자체 제공 (DOM API 등)
    타이머 관리 Node.js의 setTimeout, setInterval 브라우저의 setTimeout, setInterval
    I/O 처리 비동기 I/O 작업, 파일 시스템 접근, 네트워크 요청 처리 사용자 이벤트, 네트워크 요청, DOM 조작
    태스크 큐 (Task Queue) 마이크로태스크 큐와 매크로태스크 큐 구분 마이크로태스크 큐와 매크로태스크 큐 구분
    마이크로태스크 process.nextTick, Promise Promise, MutationObserver
    매크로태스크 I/O 작업, 타이머 콜백, setImmediate 사용자 이벤트, 타이머 콜백, 네트워크 이벤트
    렌더링 없음 렌더링 엔진과 협력하여 UI 업데이트
    추가 기능 클러스터링, 스트리밍, 네트워크 프로토콜 지원 브라우저 API, DOM 조작, CSSOM 처리
    주요 차이점 설명
    1. 환경:
      • Node.js 이벤트 루프는 서버 사이드 환경에서 실행되며, 주로 서버에서 비동기 I/O 작업을 처리하는 데 중점을 둔다.
      • 브라우저 이벤트 루프는 클라이언트 사이드 환경에서 실행되며, 사용자 인터페이스 이벤트 및 비동기 작업 처리를 주로 한다.
    2. 기반 엔진 및 핵심 모듈:
      • Node.js는 V8 JavaScript 엔진을 기반으로 하고, libuv를 통해 이벤트 루프를 구현한다.
      • 브라우저는 다양한 JavaScript 엔진(V8, SpiderMonkey, JavaScriptCore 등)을 사용하며, 브라우저 자체에서 이벤트 루프를 제공한다.
    3. I/O 처리 및 타이머 관리:
      • Node.js 이벤트 루프는 파일 시스템 접근, 네트워크 요청 등 서버 측 비동기 I/O 작업을 효율적으로 처리한다.
      • 브라우저 이벤트 루프는 사용자 이벤트, 네트워크 요청, DOM 조작 등 클라이언트 측 비동기 작업을 처리한다.
    4. 렌더링:
      • Node.js는 서버 사이드 환경으로, 렌더링 작업이 필요하지 않다.
      • 브라우저는 렌더링 엔진과 협력하여 UI 업데이트를 수행한다.
    5. 추가 기능:
      • Node.js는 클러스터링, 스트리밍, 네트워크 프로토콜 등의 추가 기능을 제공한다.
      • 브라우저는 브라우저 API, DOM 조작, CSSOM 처리 등 다양한 클라이언트 사이드 기능을 제공한다.
    두 이벤트 루프는 비동기 작업을 처리하는 공통적인 목적을 가지고 있지만, 각 환경의 요구사항에 맞춰 설계되었다. Node.js 이벤트 루프는 서버 측의 고성능 비동기 I/O 처리를, 브라우저 이벤트 루프는 사용자 인터페이스의 부드러운 동작을 목표로 한다.Node.js에서 I/O를 직접 수행하는 함수는 거의 없으므로 프로세스는 블로킹되지 않는다. 그러므로 Node.js에서는 확장성 있는 시스템을 개발하는 게 아주 자연스럽다.블로킹모델 문제점
    • 사용자 경험 저하:
      • 브라우저 환경에서 자바스크립트가 블로킹 작업을 수행하면, 해당 작업이 완료될 때까지 사용자가 페이지와 상호작용할 수 없다. 이는 페이지가 "멈추는" 경험을 하게 만들며, 사용자의 인터페이스가 응답하지 않게 된다.
    • 전체 애플리케이션 정지:
      • 자바스크립트는 싱글 쓰레드 언어이므로, 하나의 작업이 블로킹되면 다른 모든 작업이 중단된다. 이는 서버 측에서도 문제가 될 수 있으며, Node.js 서버의 경우 모든 클라이언트 요청이 중단되는 상황이 발생할 수 있다.
    • 성능 저하:
      • 블로킹 작업이 길어질수록 전체 애플리케이션의 응답성이 저하된다. 이는 특히 고성능, 고확장성 서버가 요구되는 환경에서 큰 단점이 된다.
    블로킹 코드 (문제점 발생)위 코드는 5초 동안 CPU를 점유하며 다른 작업을 차단한다. 브라우저에서는 이 시간 동안 페이지가 멈추고, Node.js 서버에서는 모든 요청이 대기 상태가 된다.
    javascript코드 복사
    console.log("Start");
    
    setTimeout(() => {
        console.log("End");
    }, 5000); // 5초 후에 콜백 실행 (비동기)
    
    console.log("Continuing execution...");
    
    
    위 코드는 setTimeout을 사용하여 비동기적으로 작업을 처리한다. 브라우저에서는 페이지가 계속 응답하고, Node.js 서버에서는 다른 요청을 처리할 수 있게 된다.자바스크립트는 비동기 프로그래밍을 위해 콜백, 프라미스(Promises), 그리고 async/await 같은 패턴을 제공한다. 이를 통해 싱글 쓰레드 환경에서도 블로킹 없이 비동기 작업을 효율적으로 처리할 수 있다.
    +-------------------------------------------------+
    |                     Node.js                     |
    | +---------------------------------------------+ |
    | |                V8 JavaScript Engine         | |
    | |                                             | |
    | +---------------------------------------------+ |
    | +---------------------------------------------+ |
    | |                     libuv                   | |
    | |  +----------------+  +--------------------+ | |
    | |  | 이벤트 루프    |  | 비동기 I/O          | | |
    | |  +----------------+  +--------------------+ | |
    | +---------------------------------------------+ |
    | +---------------------------------------------+ |
    | |                C++ 바인딩                   | |
    | +---------------------------------------------+ |
    | +---------------------------------------------+ |
    | |              Node.js 표준 라이브러리         | |
    | +---------------------------------------------+ |
    +-------------------------------------------------+
    
    
    libuv에 이벤트루프가 있음. libuv는 다양한 작업을 수행하는 C기반의 라이브러리다. 이벤트루프에 던져진 비동기 작업들은 이벤트 루프 내부가 아닌 system kernel에서 수행된다.
    1. V8 JavaScript 엔진:
      • 구글 크롬에서 사용하는 고성능 JavaScript 엔진이다.
      • JavaScript 코드를 머신 코드로 변환하여 빠르게 실행한다.
    2. libuv:
      • 비동기 I/O를 처리하는 라이브러리다.
      • 이벤트 루프, 파일 시스템, 네트워크 작업 등을 관리하며, 크로스 플랫폼 비동기 I/O 기능을 제공한다.
    3. C++ 바인딩:
      • Node.js의 많은 핵심 모듈은 C++로 작성되어 있으며, V8과 libuv와 상호작용한다.
      • 고성능의 네이티브 코드와 JavaScript 코드 간의 인터페이스를 제공한다.
    4. 이벤트 루프:
      • Node.js의 핵심 구성 요소로, 비동기 작업을 관리하고 실행하는 역할을 한다.
      • 다양한 큐를 사용하여 작업을 관리하며, 비동기 I/O 작업, 타이머, process.nextTick, Promise 등을 처리한다.
    5. Node.js 표준 라이브러리:
      • 파일 시스템, 네트워크, 스트림, 버퍼, 암호화 등 다양한 기능을 제공하는 내장 모듈 모음이다.
      • 개발자가 다양한 기능을 쉽게 사용할 수 있도록 API를 제공한다.
    각 구성 요소의 역할
    1. V8 JavaScript 엔진:
      • JavaScript 코드를 컴파일하고 실행하는 역할을 한다.
      • 성능을 극대화하기 위해 최적화된 JIT(Just-In-Time) 컴파일을 사용한다.
    2. libuv:
      • 이벤트 루프와 비동기 I/O 작업을 관리하는 역할을 한다.
      • 운영 체제의 기능을 추상화하여 크로스 플랫폼 지원을 가능하게 한다.
      • 다음과 같은 기능을 제공한다:
        • 파일 시스템 작업 (읽기, 쓰기 등)
        • 네트워크 작업 (HTTP, TCP, UDP 등)
        • 타이머 (setTimeout, setInterval)
        • DNS 조회
        • 이벤트 루프 관리
    3. C++ 바인딩:
      • 고성능 네이티브 코드를 Node.js와 통합하는 역할을 한다.
      • V8과 libuv와의 상호작용을 위한 인터페이스를 제공한다.
    4. 이벤트 루프:
      • 비동기 작업의 실행 순서를 관리하는 역할을 한다.
      • 이벤트 루프는 다음과 같은 단계로 구성된다:
        • Timers: setTimeout과 setInterval의 콜백을 실행한다.
        • Pending Callbacks: 일부 I/O 작업의 콜백을 실행한다.
        • Idle, Prepare: 내부적으로 사용된다.
        • Poll: 새로운 I/O 이벤트를 가져오고, I/O 관련 콜백을 실행한다.
        • Check: setImmediate 콜백을 실행한다.
        • Close Callbacks: 닫힌 소켓 등의 콜백을 실행한다.
    5. Node.js 표준 라이브러리:
      • 개발자가 쉽게 사용할 수 있는 다양한 모듈을 제공한다.
      • 파일 시스템, 네트워크, 스트림, 버퍼, 암호화 등의 기능을 포함한다.
      • 이러한 모듈은 대부분 비동기로 작동하여 이벤트 루프와 함께 원활하게 동작한다.
    Node.js는 이러한 구성 요소들이 유기적으로 결합되어 비동기 I/O를 효율적으로 처리하고, 고성능의 서버 사이드 애플리케이션을 개발할 수 있도록 한다.libuv와 이벤트 루프시스템 커널의 역할비동기 작업의 흐름
    1. 이벤트 루프에 작업 등록:
      • 자바스크립트 코드에서 비동기 작업을 요청하면, libuv는 해당 작업을 이벤트 루프의 작업 큐에 등록한다.
      • 예를 들어, 파일 읽기 요청을 할 때 fs.readFile 호출은 libuv를 통해 이벤트 루프에 작업을 등록한다.
    2. 시스템 커널로 작업 위임:
      • libuv는 비동기 작업을 처리하기 위해 시스템 커널에 해당 작업을 요청한다.
      • 시스템 커널은 파일 시스템 작업, 네트워크 I/O 등의 작업을 실제로 수행한다.
      • 이 과정에서 커널은 비동기 작업의 완료 여부를 비동기적으로 이벤트 루프에 통지한다.
    3. 이벤트 루프에서 콜백 처리:
      • 시스템 커널이 작업을 완료하면, libuv의 이벤트 루프는 해당 작업에 대한 콜백을 실행한다.
      • 이 콜백 함수는 자바스크립트 코드에서 정의한 작업 완료 후의 처리를 담당한다.
    예제 흐름: 파일 읽기
    1. 비동기 파일 읽기 요청:
    2. const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error(err); return; } console.log(data); });
    3. libuv가 요청을 시스템 커널에 전달:
      • fs.readFile 호출 시 libuv는 해당 파일 읽기 작업을 시스템 커널에 요청한다.
      • 시스템 커널은 파일 읽기 작업을 시작하고, 완료될 때까지 다른 작업을 계속 처리한다.
    4. 시스템 커널에서 작업 완료:
      • 시스템 커널이 파일 읽기를 완료하면, 이 정보를 libuv에 통지한다.
    5. libuv 이벤트 루프가 콜백 실행:
      • 이벤트 루프는 파일 읽기 작업이 완료된 것을 감지하고, 등록된 콜백 함수를 실행한다.
      • 콜백 함수는 읽어온 파일 내용을 출력하거나 에러를 처리한다.
    결론

    정리

    • Node.js는 V8엔진의 등장과 함께 개발된 자바스크립트 런타임 환경
    • 비동기 이벤트 주도, 논-블로킹으로 효율적이고, 확장성있는 네트워크 앱을 만들 수 있도록 설계
    • libuv를 이용해 비동기 작업을 시스템 커널에 위임하며 동작
  • libuv는 Node.js의 이벤트 루프를 통해 비동기 작업을 관리하지만, 실제 작업의 많은 부분은 시스템 커널에서 수행된다. 이는 libuv가 고성능, 비동기 I/O를 효율적으로 처리할 수 있는 이유 중 하나다. 이벤트 루프는 이러한 작업의 상태를 모니터링하고, 작업이 완료되면 적절한 콜백을 실행하여 비동기 프로그래밍 모델을 구현한다.
  • 비동기 작업의 많은 부분은 libuv 이벤트 루프 내부에서 직접 수행되지 않고, 시스템 커널에 의해 처리된다. 시스템 커널은 운영체제의 핵심 부분으로, 하드웨어와 직접 상호작용하며 다양한 저수준 작업을 처리한다.
  • libuv의 이벤트 루프는 Node.js의 비동기 작업을 관리하는 중심 역할을 한다. 이벤트 루프는 다양한 비동기 작업을 큐에 넣고, 순차적으로 처리하는 방식으로 동작한다. 이벤트 루프가 처리하는 주요 작업에는 파일 시스템 I/O, 네트워크 I/O, 타이머, DNS 조회 등이 포함된다.
  • libuv는 Node.js의 핵심 라이브러리로, 비동기 I/O 작업을 관리하고 처리하는 역할을 한다. libuv의 이벤트 루프는 다양한 작업을 관리하지만, 실제로 비동기 작업의 많은 부분은 시스템 커널에서 수행된다. 이를 이해하기 위해 libuv의 이벤트 루프와 시스템 커널 간의 상호작용을 자세히 설명하겠다.
  • Node.js의 내부 구조는 다음과 같은 주요 구성 요소로 이루어져 있다:
  • 노드의 내부 구조
  • 자바스크립트의 비동기 패러다임
  • 비동기 코드 (문제 해결)
  • javascript코드 복사 function sleep(milliseconds) { const start = Date.now(); while (Date.now() - start < milliseconds) { // 아무것도 하지 않음 (블로킹) } } console.log("Start"); sleep(5000); // 5초 동안 블로킹 console.log("End");
  • 블로킹 모델에서는 작업이 완료될 때까지 현재 쓰레드가 멈추게 된다. 이를 자바스크립트 환경에 적용했을 때 발생하는 문제점은 다음과 같다:
  • 자바스크립트는 싱글쓰레드 언어이므로 블로킹모델을 사용할 수 없음!
  • 논 블로킹 I/O 모델
  • 근본적으로 차이는 별로 없고..
  • nodejs event loop vs brower event loop
  • 목록이 비게되면
  • 위에서부터 차례대로 실행, 특정시간을 할당해서 그시간만큼 작업을 처리하는 라운드 로빈 방식
  • Nodejs의 실행 방식
  • 이벤트 주도 방식 vs 쓰레드 기반 동시성 모델
  • 아래는 간단한 HTTP 서버를 만드는 예제다. 클라이언트 요청이 들어올 때마다 'request' 이벤트가 발생하고, 등록된 핸들러가 실행된다.
  • Node.js에서 이벤트 주도 방식(Event-Driven Programming)은 비동기 프로그래밍 모델로, 시스템이 발생하는 이벤트(예: 사용자 입력, 메시지 도착, 타이머 종료 등)를 기반으로 동작하는 프로그래밍 패러다임이다. Node.js의 핵심 개념 중 하나로, 특히 서버 애플리케이션을 작성할 때 매우 유용하다.
  • 자바스크립트에서 비동기를 처리하는 방법: Async, await, Promise, callback…
  • 비동기 이벤트 주도 Javascript 런타임으로써 Nodejs는 확장성 있는 네트워크 어플리케이션을 만들 수 있도록 설계되었다.
  • 크롬브라우저는 더 빨리 js를 실행할 수있게됨 V8엔진코드도 오픈소스로 공개됨
  • 자바스크립트를 실행시키는 런타임 환경
반응형

최근댓글

최근글

© Copyright 2023 jngmnj