: 리소스(기다리고 있던 DB의 목적 리소스)에서 새 이벤트를 사용할 수 있을때까지 디멀티플렉서가 차단되다가, 처리된 다음 이벤트 큐로 전해지고, 이벤트 루프에 의해 핸들러가 호출되어 반응하는 것
이벤트 디멀티플렉싱
: Non-blocking 리소스를 처리하기 위한 기본적인 메커니즘
- Disk I/O작업은 기본적으로 블로킹 I/O인데, 이걸 매번 block시키면 해당 스레드의 유휴시간이 길어지기 때문에 효율적으로 바꿔야 한다.
- 하나의 연결은 한 thread로 처리되는데, block이 많으면 위와같이 유휴시간이 길어진다.
- 동시성을 위해서 각 연결 당 스레드 풀에서 스레드 가져와 할당해줄텐데, 이처럼 스레드 낭비(유휴시간)이 많다면 메모리를 소비하고 context switch를 유발하고, 낭비이다.
- 따라서, 각 연결당 짧은 연결을 가지면서 context swtich를 유발하지 않는 것이 좋다.
Non-blocking으로 만드는 방법
- Polling 방식: 매번 리소스를 받았는지 계속 확인하는 것은 Busy waiting이고, CPU를 계속 사용해야 해서 비효율적이다.
- 동기 이벤트 디멀티플렉서: 감시중인 리소스들로부터 들어오는 I/O 이벤트를 이벤트 큐에 넣고, 처리할 새 이벤트 있을때까지 다시 차단
Reactor 패턴
: 각 I/O 작업과 관련된 핸들러를 갖는 것. Javascript의 Callback은 리액터 패턴의 핸들러를 구현한 것.
- 이벤트가 생성되어 디멀티플렉서에 의해 이벤트 큐로 전해지고, 이벤트 루프에 의해 처리되는 즉시 각 핸들러는 호출된다.
- 핸들러는 (5a)실행을 완료해 이벤트 루프에 제어를 반환할 수도, 혹은 새로운 비동기 요청(5b)이 발생해, 제어가 이벤트 루프로 돌아가기 전에디멀티플렉서에 새로운 이벤트를 등록(1)할 수도 있다.
- 디멀티플렉서에 의해 처리 될 일이 없고, 이벤트 큐가 비어있게 되면 Node.js 어플리케이션은 끝난다.
libuv
: 운영체제마다 이벤트 디멀티플렉서를 위한 자체 인터페이스가 있으나, 불일치가 있을 수 있다. libuv라는 C 라이브러리를 통해 기본 시스템 호출을 추상화해, 문제를 해결
- 또한, 해당 libuv는 Reactor 패턴을 구현하고 있어 이벤트 루프 생성, 이벤트 큐 관리 등에 대한 API를 제공한다.
Reference)
Node.js 디자인패턴