Node.js

[Node.js] Libuv 이벤트 루프

이경찬 :) 2024. 1. 8. 13:25

Node.js에서 Javascript코드의 세부 실행 흐름분석

 

1. js로 작성된 코드를 node.js로 실행

 

2. 이벤트 루프에 진입하기 전에 코드를 실행

 

- Node.js는 I/O작업 (ex: 파일 시스템 작업, 네트워크 요청) 또는 타이머 (ex: `setTimeout`)와 같은 비동기 작업이 발생할 때까지 동기 코드를 실행합니다.

 

3.비동기 작업 및 libuv

 

  • libuv에 작업 위임: 4. 파일 시스템(fs) 작업이나 소켓 통신 등 libuv와 관련된 기능이 발생하면 제어가 차단되지 않습니다. 대신 libuv가 이러한 작업을 비동기적으로 인계받아 처리합니다.
  • 동기식/비동기식 확인: 5. libuv는 작업이 동기식인지 비동기식인지 확인합니다. 동기 작업의 경우 시스템 API를 직접 사용할 수 있습니다. 비동기 작업의 경우 libuv 스레드 풀에서 생성된 스레드에 작업을 위임할 수 있습니다.
  • 콜백 등록: 6. 작업을 수행한 후(시스템 API를 사용하거나 스레드 풀의 스레드에서) libuv는 작업이 완료될 때 실행될 콜백을 대기열에 등록합니다.

 

4. 코드들을 마저 실행

 

5. 코드들을 다 실행했으면 이벤트루프를 만들지, 종료할지 결정 (libuv에 의해 콜백이 등록되었다면 이벤트 루프 생성, 업승면 프로그램 종료)

 

  • 콜백 확인:  모든 동기 코드가 실행되면 Node.js는 대기열에 libuv에 의해 등록된 콜백이 있는지 확인합니다.
  • 이벤트 루프 생성 또는 종료: 콜백이 있는 경우 Node.js는 이벤트 루프를 생성하여 이러한 작업 처리를 시작합니다. 콜백이 없으면 더 이상 수행할 작업이 없으면 프로그램이 종료될 수 있습니다.

6. 이벤트 루프는 timers -> pending callbacks -> idle, prepare -> poll -> check -> close callback과 같은 순으로 큐에 등록된 작업을 실행

 

Node.js 이벤트 루프 이해하기:

1. 단일 스레드 비동기 모델:

Node.js는 단일 스레드 이벤트 중심 모델에서 작동하므로 과도한 스레드 없이도 수많은 동시 연결을 처리할 수 있습니다. 이는 I/O 작업과 비동기 작업을 효율적으로 관리하는 이벤트 루프를 통해 가능합니다.

2. libuv 라이브러리:

Node.js 이벤트 루프의 핵심에는 기본 운영 체제의 비동기 I/O 작업을 추상화하는 크로스 플랫폼 라이브러리인 libuv 라이브러리가 있습니다. libuv는 Node.js가 다양한 플랫폼에서 실행될 수 있도록 보장하여 이벤트 처리 및 동시성 관리를 위한 일관된 인터페이스를 제공합니다.

Node.js 이벤트 루프의 단계:

1. 타이머:

  • 타이머 단계에서는 예약된 콜백 함수가 실행됩니다. 이러한 콜백은 setTimeout 또는 setInterval 함수의 결과입니다. 타이머가 만료되면 관련 콜백이 이벤트 루프의 다음 단계에 추가됩니다.

2. I/O 콜백:

  • I/O 콜백 단계는 파일 시스템 작업이나 네트워크 요청과 같은 I/O 작업의 콜백을 처리합니다. 이 단계는 비동기 작업을 효율적으로 관리하고 I/O 바인딩 작업이 기본 스레드를 차단하지 않도록 하는 데 중요합니다.

3. 유휴 상태, 준비:

  • 이러한 단계는 덜 일반적으로 사용되지만 개발자가 유휴 기간 동안 코드를 실행하거나 후속 이벤트를 위해 시스템을 준비할 수 있는 기회를 제공합니다.

4. Poll

  • 폴링 단계는 Node.js가 새로운 이벤트가 발생할 때까지 기다리는 단계입니다. 보류 중인 이벤트가 없으면 I/O 이벤트가 완료될 때까지 기다립니다. 이 단계에서는 이벤트 루프가 응답성을 유지하여 애플리케이션이 사용자 상호 작용이나 외부 입력을 즉시 처리할 수 있도록 합니다.

5. 콜백 확인, 닫기:

  • 확인 단계에서는 setImmediate 함수를 통해 추가된 콜백을 처리합니다. 또한 이 단계에서는 닫기 콜백이 실행되어 이벤트가 처리된 후 리소스를 해제하는 방법을 제공합니다.

별도 단계의 장점:

1. 효율적인 자원 활용:

  • 단계 분리를 통해 Node.js는 시스템 리소스를 효율적으로 활용할 수 있습니다. 각 단계는 특정 유형의 작업에 전념하여 불필요한 차단을 방지하고 이벤트 루프가 다양한 유형의 이벤트에 신속하게 응답할 수 있도록 보장합니다.

2. 예측 가능한 실행 흐름:

  • 이벤트 루프의 잘 정의된 단계는 예측 가능하고 이해 가능한 실행 흐름을 만듭니다. 개발자는 콜백이 실행되는 순서를 추론할 수 있으므로 애플리케이션을 더 쉽게 설계하고 최적화할 수 있습니다.

3. 지연 시간 단축:

  • 불필요한 차단을 방지하고 I/O 작업을 효율적으로 관리함으로써 별도의 단계를 갖춘 이벤트 루프가 대기 시간을 줄입니다. 이는 여러 동시 연결을 처리하는 웹 서버와 같이 실시간 응답이 필요한 애플리케이션에 중요합니다.

4. 확장성:

  • 이벤트 루프의 디자인은 Node.js 애플리케이션의 확장성에 기여합니다. 비차단 특성과 단계 분리를 통해 시스템은 리소스 소비를 비례적으로 늘리지 않고도 많은 수의 동시 연결을 처리할 수 있습니다.

5. 개발자를 위한 유연성:

  • 개발자는 별도의 단계에서 제공되는 유연성의 이점을 누릴 수 있습니다. 작업의 성격에 따라 코드를 다양한 단계에 전략적으로 배치하여 특정 시나리오 및 워크로드에 맞게 애플리케이션을 최적화할 수 있습니다.

결론:

libuv 라이브러리로 구동되고 별도의 단계로 구성된 Node.js의 이벤트 루프는 확장 가능하고 반응성이 뛰어난 애플리케이션을 성공적으로 구축하는 데 있어 초석입니다. 타이머부터 I/O 콜백까지 이러한 단계 뒤에 있는 디자인 선택은 이벤트 루프의 효율성, 예측 가능성 및 대기 시간 감소에 기여합니다. 개발자가 Node.js의 강력한 기능을 활용함에 따라 이 이벤트 루프 구조의 장점을 이해하는 것은 오늘날의 동적이고 까다로운 소프트웨어 LAN에서 고성능 애플리케이션을 제작하는 데 중추적인 역할을 합니다.