1-1 Node.js의 철학
1-1-1. 라이트 코어
– 최소한의 기능으로 코어를 관리하기 위해 Node.js 코어 외부에 userland/userspace라는 순수 사용자 모듈 생태계가 형성됩니다.
※ Userland, UserSpace: 커널 공간이 아닌 사용자 메모리 공간에서 실행되는 라이브러리
1-1-2. 라이트 모듈
– Node.js는 재사용 가능한 라이브러리를 만드는 기본 수단으로 모듈 개념을 사용합니다.
코드의 양과 범위 측면에서 작은 모듈을 설계하는 것은 Node.js의 공통 원칙입니다(1 프로그램 – 1 규칙).
– 소형 모듈 구성의 장점
1) 재사용성 ↑
2) 이해하기 쉽고 사용하기 쉽다.
3) 테스트 및 유지 보수가 용이함
4) 작은 크기로 브라우저에서 보다 쉽게 사용할 수 있습니다.
– NPM(패키지 관리자)의 도움으로 각 패키지는 필요한 종속성 버전을 가질 수 있습니다.
충돌 방지뿐만 아니라 많은 수의 작은 제약 조건을 허용합니다.
– DRY(Don’t Repeat Yourself) 원칙: 반복하지 마십시오!
1-1-3. 작은 외부 인터페이스
– Node.js 모듈은 단일 진입점을 제공합니다(하나의 함수 또는 클래스만 노출하고 사용하도록 구성됨).
– 모듈 내부로의 접근을 제한하여 확장의 가능성을 줄이되, 이는 본질적인 기능에 집중되어 사용성을 향상시키는 경향이 있습니다.
1-1-4. 단순함과 실용주의
– KISS(Keep it Simple, Stupid) 원칙: 기능은 적지만 단순한 것이 소프트웨어 디자인에 더 좋습니다.
– node.js가 자바스크립트를 기반으로 하는 이유는 자바스크립트가 편리한 언어이기 때문입니다.
1-2 Node.js 코어 작동 방식
1-2-1. 논블로킹 I/O
– 블로킹 I/O는 다중 스레드를 통해 여러 동시 연결을 처리하지만 많은 리소스가 메모리 소비 및 컨텍스트 전환에 낭비됩니다.
– Non-blocking I/O는 즉시 반환되기 때문에 리소스에 읽을 준비가 된 데이터가 없으면 오류가 발생합니다.
따라서 논블로킹 I/O가 데이터를 처리하는 방법이 중요합니다.
– Synchronous Event Demultiplexer(Event Notification Interface): 여러 리소스를 모니터링하고 읽기/쓰기 작업이 완료되면 새 이벤트를 반환하는 방식입니다.
새 이벤트가 반환될 때까지 차단됩니다.
이를 통해 단일 스레드가 여러 리소스의 I/O를 처리할 수 있습니다.
watchedList.add(socketA, FOR_READ)
watchedList.add(fileB, FOR_READ)
while(events = demultiplexer.watch(watchedList)){
for (event of events){
data = event.resource.read()
if(data === RESOURCE_CLOSED) {
demultiplexer.unwatch(event.resource)
} else {
consumeData(data)
}
}
}
1-2-2. 원자로 패턴
– 각 I/O 작업과 관련된 핸들러(콜백 함수)가 있으며 리소스가 준비되면 이벤트 루프에서 콜백 함수를 호출하고 리소스를 가져옵니다.
1-2-3. Libuv(node.js I/O 엔진 라이브러리)
– 디멀티플렉서를 위한 자체 인터페이스가 있습니다.
B. Linux의 epoll, macOS의 kqueue 및 Windows I/O Completion Port(IOCP) API.
– 각 I/O 및 OS가 다르게 작동할 수 있으므로 Node.js는 OS 호환성 및 다양한 리소스 유형의 비차단 작업을 표준화하는 Libuv 라이브러리를 사용합니다.
– 시스템 호출 추상화 및 응답 패턴 구현(이벤트 루프 생성, 이벤트 큐 관리 및 비동기 I/O 작업 수행)과 같은 기능을 수행합니다.
1-3 Node.js의 자바스크립트
1-3-1. 네이티브 코드 실행
– Node.js는 N-API 인터페이스를 통해 네이티브 코드에 바인딩할 수 있는 사용자 측 모듈을 만들 수 있습니다.
N-API는 네이티브 코드와 연결된 공유 객체(애드온)를 생성하기 위한 API이며, 모듈은 C 또는 C++를 사용하여 작성해야 합니다.
– C/C++ 라이브러리를 가져와서 사용할 수 있고 하드웨어 드라이브/포트와 같은 하위 수준 기능에 대한 액세스를 제공할 수 있으므로 오픈 소스 재사용이 가능합니다.