Node.js 동작원리
Event-Driven(이벤트 기반)
이벤트(클릭, 또는 네트워크 요청 등) 발생시 미리 지정해둔 작업을 수행한다.
이렇게 하기 위해 특정 이벤트 발생시 무엇을 할지 미리 등록을 해놓는다. (Event listener에 callback함수 등록)
우선 정확한 구조를 보기 위해 용어들 부터 간략하게 설명해보자.
Call Back함수: 다른 함수의 인자로 넘겨지는 함수 및 어떤 이벤트에 호출되어지는 함수이다.
Event Loop: 이벤트 발생시 호출할 call back 함수 관리 및 호출된 call back 함수 실행 순서 결정. Node가 종료될때까지 이벤트 처리 작업을 반복한다.
Background: event listener가 대기하는곳이다.
Task Queue: 이벤트 발생후, 백그라운드에서 taskqueue로 콜백함수를 보낸다.
우선 저 호출스택에 함수들이 쌓이면 가장마지막에 쌓인것부터 background로 보내집니다(여기서는 web api). 그 후 콜백함수는 task queue로 보내집니다. 그 다음 호출 스택에 쌓인 것이 또 빠집니다. 호출 스택이 빌때 까지 이 작업을 반복한 후 호출 스택이 비면 Task Queue에 있는 콜백함수를 호출 스택으로 올려줍니다. 그 후 또 call stack 이 빌때까지 실행합니다.
이게 기본적인 javascript가 실행되는 방식입니다.
노드의 경우 비슷한 작업을 libuv라는 c언어로 된 라이브러리가 처리해줍니다.
Non-Blocking I/O
우선 Blocking과 Non-Blocking의 차이를 간단하게 보자.
Blocking: 함수를 호출하면 제어권을 같이 넘겨주게 되는데 이때 호출된 함수가 작업이 끝날때 까지 제어권을 반환하지 않고 대기
Non-Blocking: 위와 같이 함수를 호출하면 제어권을 같이 넘겨주게 되는데 호출된 함수가 바로 제어권 반환해 대기하지 않고 다른 작업 진행
여기서 주의할 점은 Non-Blocking이라고 해서 Javascript코드가 동시에 실행되는것은 아니다.
하지만 Javascript상에서가 아닌 I/O작업 같은 건 동시에 처리할 수 있다.
이렇게 동시에 처리가 가능한 작업들을 Non-Blocking이 더욱 빠르게 처리한다.
Node의 경우 I/O작업을 백그라운드로 넘겨 동시에 처리한다. 이렇게 동시에 처리될 수 있는 작업들을 최대한 묶어 백그라운드로 넘겨야 시간절약을 할 수 있다. 그래서 우리는 코드를 짤때 실행 순서를 바꿔서 간단한 작업이 대기하는 상황이 오지 않도록 짜야한다.
Single Thread
Thread가 하나뿐이라는 것이다.
우선 Process와 Thread 에 대해 간단히 알아보자.
Process: 운영체제에서 할당하는 작업단위, 노드 또는 web brower같은 프로그램은 개별적 프로세스이다. 또 프로세스간에 자원공유는 하지 않는다.
Thread: 프로세스 내에서 실행하는 흐름의 단위이다. 프로세스에서 여러개의 thread를 생성해서 여러 작업을 동시에 수행한다. 그리고 thread간에 자원공유가 가능해 같은 데이터에 접근이 가능하다.
우선 Node실행시 process를 생성한후 이 process내에 여러개의 thread가 생성된다. 하지만 우리가 제어 할 수 있는 thread는 하나여서 single thread 라고 한다.
그럼 하나의 스레드만 직접 조작할 수 있다고 가정해보자. 요청이 많이 들어오면 한번에 하나씩 요청처리를 할 수 있다. 블로킹이 발생할 수 있는 경우 우리는 최대한 Non-Blocking방식으로 코드를 짜 시간을 줄여야 한다.
참고자료:
Node.js 교과서 개정 2판