Node.js
Node.js란, 비동기 이벤트 주도 JavaScript 런타임 환경이다.
이렇게 말하면 이해가 잘 되지 않을테니 구조를 함께 살펴보자.
Architecture
(Image from https://medium.com/yet-another-node-js-blog/architecture-of-node-js-internal-codebase-57cd8376b71f by Aren Yanqi Li)
1. V8
2. libuv
Node.js를 위해 만들어진, 비동기 I/O 기반의 Event Loop를 지원하는 C 라이브러리이다. 그렇기 때문에 Node.js에서는 네트워크 요청이나 I/O 등의 작업을 비동기적으로(즉, 여러 작업을 동시에) 처리할 수 있다. 이 라이브러리에서 다음의 기능을 제공한다.
- Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
- Asynchronous TCP and UDP sockets
- Asynchronous DNS resolution
- Asynchronous file and file system operations
- File system events
- ANSI escape code controlled TTY
- 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
3. Other C/C++ Components
가령,
crypto
(openssl),html-parser
등의 저수준의 기능을 제공한다.
4. Application/Modules
JavaScript Core Module, 소스 코드, npm 라이브러리 등이 포함된다.
5. C/C++ Bindings
Node.js에는 C/C++로 작성된 라이브러리가 많이 사용되는데, 따라서 이를 Node.js 환경에서 사용하기 위해 바인딩이 필요하다.
6. C/C++ Addons
그 외에 다른 third-party C/C++ 라이브러리를 포함시키기 위해서는 바인딩 하기위한 코드를 직접 작성해야한다.
Features
위의 구조를 통해 Node.js는 결국 다음의 주요 기능으로 설명될 수 있다.
1. Event-Driven Architecture와 Non-blocking I/O
Node.js는 네트워크의 요청, 사용자의 I/O 이벤트에 반응해서 동작하게 된다. 이렇게 이벤트가 발생하면 Event Loop가 이를 감지하고, 콜백함수를 호출해 백그라운드에서 이를 처리한다. 그로 인해 작업이 완료되기 전에 I/O의 작업을 차단하지 않고, 다른 요청을 처리할 수 있게 되므로 비동기 처리가 가능해진다.
2. JavaScript Core(Built-in) Module
또 중요한 것으로, JavaScript의 Core Module을 들 수 있다. 가령 crypto
, fs
, path
, http
등이 있고, 이들은 별도의 설치 없이 import 후 사용이 가능하다.
3. Single Thread
Node.js는 매 요청마다 스레드를 새로 생성하지 않고, 기본적으로 단일 스레드를 사용한다. 그렇기 때문에 Multi-Threading, Multi-Processing과는 다르다. 어떻게 가능한걸까?
사실 Node.js에서는 libuv
에서 제공하는 Worker Thread 덕분이다. Node.js 프로세스가 생성 됐을 때, 하나의 Thread가 기본적으로 되는데, 이게 Main Thread이다. Node.js에서는 메인 스레드에서 모든 요청을 다 처리한다. 그 외의 I/O 작업 등은 백그라운드에서 libuv
에 의해 유지되고 있는 Worker Thread 에서 처리한다. 따라서 I/O 작업은 메인 스레드가 아닌, Worker Thread에서 비동기적으로 처리되는 것이다. 그리고 Node.js의 libuv
가 Thread Pool에 있는 Worker Thread를 직접 관리한다.