libuv, event loop (in Node js)

김연봉·2022년 3월 29일
1

libuv

개요

멀티플랫폼을 지원하는 c 라이브러리 이다.
이벤트 루프를 기반으로 비동기 I/O 처리를 기능을 제공하고 있다.
Nodejs 에서 사용 하도록 개발 되었지만, 다른 소프트웨어에서도 사용되고 있는 중이다.
(예: Node.js, Luvit, Julia, uvloop)

주요 기능

  • Full-featured event loop backed by epoll, kqueue, IOCP, event ports.

    epoll (Linux)
    :확장 가능한 I/O 이벤트 노티피케이션 메커니즘을 위한 리눅스 커널 시스템 호출.
    I/O가 가능한지 여부를 확인하기 위해 여러 fd(파일 설명자)를 모니터링.
    현재 모니터링되고 있는 모든 파일 설명자를 추적하기 위해 RB-트리(red-black tree) 데이터 구조를 사용.

    kqueue (Unix, OSX)
    :확장 가능한 이벤트 알림 인터페이스. 여러 UNIX 환경에서 사용 되고 있음. Kqueue를 사용하는 nginx와 같은 소프트웨어가 c10k(문제는 동시에 많은 수의 클라이언트를 처리하도록 네트워크 소켓을 최적화하는 문제 Connection 10K - 10,000) 문제를 해결함.

    IOCP(Input/output completion port) (Window, Solaris)
    :여러 동시 비동기 입/출력 작업을 수행하기 위한 API.
    IOCP 개체가 생성되고 다수의 소켓 또는 파일 핸들과 연결.
    I/O 요청의 상태를 확인하기 위해 IOCP의 메시지 대기열을 확인.
    IOCP는 여러 스레드와 해당 동시성을 관리.

    event prots (Solaris)
    :이벤트 포트는 응용 프로그램이 연결되지 않은 소스에서 이벤트를 생성하고 수집할 수 있도록 하는 프레임워크. 프레임워크는 전체 성능을 저하시키지 않고 동시에 여러 개체에서 이벤트를 검색 가능.

  • Asynchronous TCP and UDP sockets
  • Asynchronous DNS resolution

    DNS resolution
    :IP 주소를 도메인 이름으로 변환하는 프로세스

  • Asynchronous file and file system operations
  • File system events
  • ANSI escape code controlled TTY

    ANSI escape code
    :ANSI 이스케이프 시퀀스 는 비디오 텍스트 터미널 및 터미널 에뮬레이터 의 커서 위치, 색상, 글꼴 스타일 및 기타 옵션을 제어하기 위한 대역 내 신호 의 표준입니다 . ASCII 이스케이프 문자와 대괄호 문자 로 시작하는 특정 바이트 시퀀스는 텍스트에 포함됩니다. 터미널은 이러한 시퀀스를 텍스트가 아닌 명령으로 해석하여 그대로 표시합니다.

  • IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
  • Child processes
  • Thread pool
  • Signal handling
  • High resolution clock
  • Threading and synchronization primitives

디자인 개요

  • libuv는 원래 Node.js 용으로 작성된 크로스 플랫폼 지원 라이브러리이고, 이벤트 기반 비동기 I/O 모델을 중심으로 설계되었다.
    라이브러리는 다양한 I/O 폴링 메커니즘에 대한 단순한 추상화 이상의 것을 제공한다. 무엇보다도 크로스 플랫폼 파일 I/O 및 스레딩 기능도 제공된다.

  • handle, requests
    libuv는 사용자에게 이벤트 루프와 함께 작업할 2가지 추상화(handle 및 reqeusts)를 제공.

    handle
    :수명이 긴 특정 작업을 나타냄. (예: 준비 핸들은 활성 상태일 때 루프 반복마다 한 번 호출되는 콜백을 가져옴)

    requests
    : 단기 작업을 나타냅니다. 핸들을 통해 이러한 작업을 수행. 쓰기 요청은 핸들에 데이터를 쓰는 데 사용. 또는 독립 실행형: getaddrinfo 요청은 루프에서 직접 실행되는 핸들이 필요않음.

  • The I/O Loop
    I/O(또는 이벤트) 루프는 libuv의 중심 부분임.
    모든 I/O 작업에 대한 내용을 설정하고 단일 스레드에 연결됨.
    각각이 다른 스레드에서 실행되는 한 여러 이벤트 루프를 실행. libuv 이벤트 루프(또는 루프나 핸들과 관련된 다른 API) 는 달리 명시된 경우를 제외하고는 not thread safety

    thread safety
    :여러 쓰레드가 데이터에 액세스할때에 구현에 경쟁조건이 없음을 보장.

    *중요: libuv는 스레드 풀을 사용하여 비동기 파일 I/O 작업을 가능하게 하지만 네트워크 I/O는 항상 각 루프의 스레드인 단일 스레드에서 수행.

  • File I/O
    네트워크 I/O와 달리 libuv가 의존할 수 있는 플랫폼별 파일 I/O 프리미티브가 없으므로 현재 접근 방식은 스레드 풀에서 차단 파일 I/O 작업을 실행.

Event Loop

이벤트 루프는 가능하다면 언제나 시스템 커널에 작업을 떠넘겨서 Node.js가 논 블로킹 I/O 작업을 수행하도록 해줍니다.(JavaScript가 싱글 스레드임에도 불구하고)

대부분의 현대 커널은 멀티 스레드이므로 백그라운드에서 다수의 작업을 실행할 수 있습니다. 이러한 작업 중 하나가 완료되면 커널이 Node.js에게 알려주어 적절한 콜백을 poll 큐에 추가할 수 있게 하여 결국 실행되게 합니다. 이 글 후반부에서 더 자세한 내용을 설명할 것입니다.

  • 이벤트 루프 다이어그램

timers: 이 단계는 setTimeout()과 setInterval()로 스케줄링한 콜백을 실행.

pending callbacks: 다음 루프 반복으로 연기된 I/O 콜백들을 실행.

idle, prepare: 내부용으로만 사용합니다.

poll: 새로운 I/O 이벤트를 가져옵니다. I/O와 연관된 콜백(클로즈 콜백, 타이머로 스케줄링된 콜백, setImmediate()를 제외한 거의 모든 콜백)을 실행합니다. 적절한 시기에 node는 여기서 블록 합니다.

check: setImmediate() 콜백은 호출.

close callbacks: 일부 close 콜백들, (예: socket.on('close', ...))

process.nextTick()

process.nextTick()이 비동기 API에 속해있지만, 다이어그램에는 표시되지 않은 것을 눈치챘을 겁니다. 이는 process.nextTick()이 기술적으로는 이벤트 루프의 일부가 아니기 때문입니다. 대신 nextTickQueue는 이벤트 루프의 현재 단계와 관계없이 현재 작업이 완료된 후에 처리될 것입니다.

profile
사랑과 자유가 있는 삶을 살아내려는 개발자 입니다.

0개의 댓글