키워드
→ libuv, 이벤트 루프
노트
- libuv 그리고 이벤트 루프에 대해 좀더 자세히 알아보자
- 파일 입출력과 관련된 것은 libuv 스레드(기본 4개)가 담당을 한다. 그 이외에 소켓 생성/삭제와 관련 된 것들은 커널에서 지원하므로, 커널에 위임한다.
- 이벤트 루프
- Node.js 의 핵심이되는 부분이다. 이벤트 루프는 언뜻 보면 하나의 메시지큐 라고 생각할 수 있지만 실제로 그렇지 않다.
- 이벤트 루프는 비동기 작업을 처리하기 위해 사용된다. 여기서 비동기작업은 주로 File I/O를 말한다.
- 이벤트 루프에는 각 이벤트가 가지는 페이즈(Phase) 별 큐가 구분되어 있다.
- 비동기 작업이 어떤 성격을 지니고 있느냐에 따라 페이즈가 달라진다.
- 페이즈는 다음과 같이 구분된다.
- Timer
- Pending Callback
- Idle
- Poll
- Check
- Close Callback
- 순서대로
- Timer는 setTimeout, setInterval 과 같은 것들을 다룬다. 내부적으로 min-heap 을 쓰고 있어서, 탐색 없이 다음에 처리해야할 작업을 바로 가져올 수 있다. 콜백 자체를 지니지는 않으며, 콜백을 가리키고 있다가 실행 순서가 되면 콜백을 호출한다.
- 참고로 setTimeout에서 1s 만큼 딜레이를 주면 항상 1s 를 정시에 보장하지 않는다. 이는 TimerPhase에서 1s 이후에 해당 콜백을 가리키는 타이머 자체를 호출하는 것이지, 콜백 자체를 호출하는 것은 아니기 때문.
- Poll은 I/O 이벤트를 다룬다. 가령 데이터 베이스에 쿼리를 보내고 결과를 실행하는 콜백, HTTP 요청을 보낸 후 응답이 왔을 때 실행되는 콜백, 파일이 비동기로 읽고 다 읽었을 때 실행되는 콜백등을 다룬다.
- Pending Callbacks 라고 불리는 단계에서는, TCP오류 같은 시스템 작업의 콜백을 반환한다. 예를들어, TCP 소켓이 연결을 시도하다가
ECONNREFUSED
같은 메시지를 받으면, 이에 대한 오류보고를 위해 이에 대한 콜백함수가 IO Callbacks (pending callbacks) 단계의 큐에 추가 된다. - Close 콜백은,
socket.on('close', () => {})
와 같은 close 타입의 핸들러를 처리하는 페이즈다. - 이벤트 루프와 별개로 Node.js 에서 구현하여 사용하는 두가지 큐가 있다.
- nextMicroQueue
process.nextTick()
의 콜백을 관리하는 큐이다.- microStackQueue
- resolve 상태의 Promise 콜백을 가지는 큐이다.
- 위 두개는 페이즈와 상관없이, 현재 작업이 끝나면 그 즉시 바로 수행한다.
- 이벤트 루프의 흐름
- Node 에서는 프로그램이 시작되면(node index.js 와 같이 실행하는 경우) 이벤트 루프를 먼저 생성한다.
- 그리고 이벤트 루프 바깥에서
index.js
를 처음부터 끝까지 실행한다. - 끝까지 실행 한 후 이벤트 루프에 남아있는 작업이 있는지를 확인한다.
index.js
가 아무런 비동기 작업도 호출하지 않았더라면 바로 종료된다. 그러나 비동기코드가 있는 경우(setTimeout, IO 작업 등)에 index.js 가 끝나고도 이벤트 루프에 남아 있는 작업이 존재한다. 따라서 이벤트 루프로 진입한다.- Node는 Timer Phase를 지나 순서대로 Pending Callbacks, Idle, Prepare, Poll, Check, Close Callback 을 지난다. 만약 여기까지도 이벤트루프에 남아있는 작업이 없으면, 종료한다. 아니라면 다시 반복한다.
- libuv
- I/O 를 담당하는 C/C++ 라이브러리, 커널을 추상화하여 비동기 API를 쓸 수 있게 한다.
- libuv는 자체적으로 스레드풀을 가지고 있기도 하고 커널에 위임해서 I/O를 처리하기도 한다.
- libuv는 커널이 어떤 비동기 API를 지원하는지 알고 있다.
- System call 참조
- 따라서, 커널이 지원하지 않는 비동기 API는 스레드 풀에 작업을 요청한다.
- 즉, Node는 I/O 작업을 자신이 아닌 다른 스레드(libuv의 스레드)를 통해 처리한다. 그래서 싱글스레드 이지만, 논 블로킹으로 I/O를 처리할 수 있는 것이다.
- 여기서 비동기 위임을 호출하는 부분이 바로 위 이벤트 루프 이다.
요약
요약: X