- node.js 란?
- 오픈 소스 크로스 플랫폼 환경으로, 개발자로 하여금 클라이언트의 브라우저 밖에서 웹앱을 실행시킬 수 있도록 한다.
- node.js를 사용함으로써 서버사이드에서 웹앱을 생성할 수 있다
- 비디오 스트리밍 사이트와 같은 I/O 집약적인 웹앱을 사용할 수 있게 한다.
- Node.js는 이벤트 기반 모델을 사용하기 때문에 데이터 집약적인 애플리케이션을 위한 완벽한 솔루션이다.
- Node.js 는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임이다. Node.js는 이벤트 기반, 논 블로킹 I/O 모델을 사용해 가볍고 효율적이다. Node.js의 패키지 생태계인 npm은 세계에서 가장 큰 오픈 소스 라이브러리 생태계이기도 한다.
- Node js는 단일 Thread 이벤트 기반 모델 이다.
- node.js를 사용하는 이유?
- Node.js는 앱 개발 회사가 확장 가능한 네트워크 프로그램을 쉽게 만들기 위해 사용하는 기술.
- 이러한 자바스크립트 런타임 환경을 사용함으로써 얻을 수 있는 장점은
- 데이터 타입 및 통합 프로그래밍 언어 제공
- 빠름
- 비동기적임
- 훌륭한 동시성
- 블록되지 않음
- node.js의 주요 기능
- 싱글스레드이지만 확장 가능함
- 빠른 코드 실행
- 버퍼링이 없음
- MIT 라이센스
- Event driven
- 비동기 API
- node.js의 작동 원리
- 클라이언트가 웹서버에 웹앱과의 상호작용을 시작하기 위한 요청을 전송함. 이러한 요청은 blocking 이거나 non-blocking으로 수행됨
- 데이터 쿼리
- 데이터 업데이트
- 데이터 삭제
- 들어온 모든 요청은 node.js가 받아 이벤트 큐에 추가한다
- 이벤트 루프에 의해 요청이 하나씩 처리된다. 여기서 요청이 간단한 요청인지, 외부 리소스를 요구하는지 하나씩 검사하고 확인한다.
- event-driven 프로그래밍이란?
- 이벤트가 각각의 함수를 트리거링하도록 개발하는 프로그래밍 접근법
- 클릭, 타이핑 등 모든 것이 이벤트가 될 수 있다
- event-driven programming에서는 이벤트가 트리거될 때마다 등록되는 콜백 함수를 가진다
- Thread 기반 vs. Event callback 방식
- Node.js는 Thread 풀을 가지긴 하나 애플리케이션 자체에는 Multi-thread 개념이 없다.
- 따라서 많은 처리를 위해 Event callback 방식을 사용한다
- Thread 기반 웹 모델은 요청이 웹 서버로 도착하면 현재 Thread 풀에 가용한 Thread에게 그 작업을 할당한다(Multi-Thread).
- 그리고 해당 요청에 대한 처리는 동일한 Thread에서 지속된다.
- 예를 들어, File을 받아오는 작업과 Data를 받아오는 작업이 있다고 하면 2개의 작업을 처리하기 위해 2개의 Thread가 생성이 되고 각각의 Thread에서 File을 받아오는 작업과 Data를 받아오는 작업을 처리하게 된다.
- 즉, Multi-Thread 방식은 서버의 요청 처리를 쓰레드에서 처리하도록 하여 병렬처리를 가능하도록 하는 방식이다.
- 쓰레드는 서버 CPU 자원을 시분할 형태로 나누어 가짐으로써 독립실행이 가능하며 다른 요청을 동시에 받을 수 있게 한다.
- 일반적으로 클라이언트의 요청마다 Thread를 발생시키다보니, 이 말은 동시 접속자 수가 많을 수록 Thread가 많이 발생한다는 의미이며 그만큼 메모리 자원도 많이 소모한다는 의미이다. 그러나 서버의 자원은 제한되어 있으므로 일정 수 이상의 Thread는 발생시킬 수 없다.
- 또한, 하나의 Thread에서 CPU를 사용하고 있다고 하면, 다른 Thread는 해당 작업이 끝날 때까지 기다려야 한다는 것이다. 즉, 동기적으로 일을 처리하게 된다.
- 이런 문제를 비동기처리로 처리하는게 Node js의 원리이다.
- 제어권을 다음 요청으로 바로 넘기기 때문에, IO 처리인 경우 Blocking 되지 않으며 다음 요청을 처리할 수 있다.
- 다시 정리해서, 단일 Thread를 사용하여 이벤트 루프를 도는데, 이벤트 큐(Task Queue)에 추가되어 있는 작업들을 순서대로 Thread에 할당해서 처리하는 방식이다.
- 클라이언트에서 요청이 들어오면 비동기 처리를 위해, 이벤트가 발생하고 서버의 이벤트 루프에 메시지 형태로 전달된다.
- 그러면, 이벤트 루프가 이를 처리할 동안, 제어권을 넘겨주고 다음 요청을 진행한다.
- 해당 요청이 완료되면 CallBack을 이용해, 완료 되었음을 알려준다.
- Blocking vs. Non-blocking / Async vs. Sync
- Blocking/non-blocking 은
제어권을 넘겨주는가 마는가의 문제이다.
- Async/Sync 는
작업이 완료되었다는 것을 신경 쓰는지 안쓰는지의 차이이다.
- A에서 B를 호출했다고 하자, 그럴때
B가 바로 제어권을 다시 A에게 넘겨준다면 non-blocking 이다.
- 그러나,
B가 끝나고 나서 A에게 제어권을 다시 넘겨준다면 Blocking이다.
- 즉 Node js는 요청이 왔을 때, 이벤트 루프에 이벤트를 주고난 후, 이벤트 루프가 바로 다음 요청에게 제어권을 넘겨주고 이벤트 루프는 해당 이벤트를 처리한다. 따라서 non-blocking 이라고 볼 수 있다.
- 또한, A에서 B를 호출할 때, A에서 callback을 넘겨주고 B가 작업을 완료한 후, callback을 실행하게 되고, A는 해당 완료를 신경쓰지 않는다면 Async 이다.
- 반면에, B가 모두 처리한 후 리턴하거나 만약 바로 제어권을 넘겨주었다하더라도 해당 처리가 끝났는지 계속해서 확인한다면 Sync이다.
- 즉, Node js의 경우 요청에 대한 처리를 이벤트루프가 완료하고 callback으로 처리한다음 끝이나기 때문에, Async라고 볼 수 있다.
- 이벤트 큐 / 이벤트 루프 과정 정리
- 흔히, URL을 이용해 우리는 서버에 원하는 요청 을 하게 된다.
- URL은 Uniform Resource Locator
- URI는 Uniform Resource Identifier
- REST API 라는 네트워크 아키텍쳐를 사용했다고 할 때, 원하는 행위(Verb) 즉, HTTP Method에 따라, URI에 표현(Representations) 된 자원(Resource) 를 이용해, 만들어 둔 Routing이 시작되고, 담당하는 함수를 찾아 실행이 되기 시작한다. (해당사항도 Event Loop 가 실행한다. )
- 요청은 여러개가 들어올 수 있는데, 이는 Socket Connection 이라고 하며, Multiplexing으로 실행이 된다. 즉, 여러 개의 socket이 동시에 연결되어 있는 상태에서 하나의 Thread( Event Loop )는 어느 socket으로부터 메시지가 들어오는지 보다가, socket에서 메시지가 들어오면, 그 메시지를 꺼내 받아서 처리한다.
- 여기서 실행은 HTTP 모듈로 실행이 될 것인데, 이 자체가 비동기 함수이므로, 실행 할 때, 앞서 Call Stack 과 Task Queue 의 실행이 이루어진다. 예를 들면, 먼저 전역 Context에서 server.run이 실행되어 Listen 상태가 될 것이고, 요청이 들어왔을 때, 연결이 확립되었을 때 Task Queue(Event Queue) 로 CallBack 이 가면서 실행이 될 것이다. 그럼 내부 실행컨텍스트에 따라 콜 스택에 저장되며 실행이 된다.
- 실행이 될 때, Non-Blocking I/O의 동작이라면, Call Stack이 없어진다면 Event Loop 가 동작하며 Event를 처리할 것이고, Blocking I/O 의 경우, 예를 들면, 파일 읽기, 데이터베이스 질의, 소켓 요청, 원격 서비스 접속 과 같은 작업이 있으면, Event Loop 는 해당 작업을 백그라운드의 Thread pool 에서 하나의 Thread 꺼내어 그곳으로 보낸다.
- 그리고 그 Thread에서 작업이 끝나 Return되면, Thread는 Event Queue 에 CallBack을 주고 Release된다.
dd0c8bbf-68fd-44e9-8b99-ce907c940e3a.pdf