[Node.js] 개념

jaylight·2021년 1월 17일
0

Node.js

Node.js는 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임입니다. Node.js는 이벤트 기반, 논블로킹 I/O 모델을 사용해 가볍고 효율적입니다. Node.js의 패키지 생태계인 npm은 세계에서 가장 큰 오픈 소스 라이브러리 생태계입니다.

Node.js is Not Server but Runtime

Runtime

Node.js는 JavaScript 런타임이다.

  • 런타임: 특정 언어로 만든 프로그램들을 실행할 수 있는 환경

    ⇒ Node.js는 자바스크립트 프로그램을 컴퓨터에서 실행할 수 있게 해준다.

기존 JavaScript는 브라우저에서만 실행이 가능했으며,
브라우저 이외 환경에서는 실행 속도 문제로 크게 활용되지 못했음

Node.js의 역사

  • 2008년 - 구글이 V8 엔진을 사용한 크롬을 출시

    다른 JavaScript 엔진에 비해 매우 빠른 속도를 자랑했으며, 오픈 소스로 코드가 공개됨

  • 2009년 - Ryan Dahl은 V8 엔진 기반의 노드 프로젝트를 시작

Node.js의 구조

  • V8
    • C, C++ 로 구현
  • libuv
    • C, C++ 로 구현
    • 노드의 특성인 이벤트 기반, 논블로킹 I/O 모델을 구현

이벤트 기반

이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식을 의미

이벤트: 클릭, 네트워크 요청 등

  • 이벤트 기반 시스템은 특정 이벤트가 발생할 때 무엇을 할지 미리 등록해두어야함

    ⇒ Event Listner에 callBack 함수를 등록해 두어야함

    버튼을 누르면 경고 창을 띄우도록 설정
    ⇒ 클릭 이벤트 리스너에 경고 창을 띄우는 콜백 함수를 등록

Node는 이벤트 기반 방식

  • 이벤트가 발생 ⇒ 이벤트 리스너에 등록해둔 콜백 함수를 호출
  • 이벤트가 없거나 발생한 이벤트를 모두 처리 ⇒ Node는 다음 이벤트가 발생할 때까지 대기

이벤트 루프

  • 여러 이벤트가 동시 발생했을 때, 어떤 순서로 콜백 함수를 호출할지를 판단
  • Node는 JavaScript 코드에서 맨 위부터 한 줄씩 실행
    & 함수 호출 부분을 발견 시 호출한 함수를 호출스택에 넣음
    function first() {
    	second();
    	console.log('첫 번째');
    }
    function second() {
    	third();
    	console.log('두 번째');
    }
    function third() {
    	console.log('세 번째');
    }
    first();
    세 번째
    두 번째
    첫 번째

위 코드를 실행 시

  1. main 함수가 호출 스택에 들어감

  2. first() 함수 호출

  3. second() 함수 호출

  4. third() 함수 호출

    호출스택은 아래와 같이 쌓임

즉, 쌓인(호출된) 순서와 반대로 실행된다.

함수 실행이 완료되면 호출 스택에서 지워지며, third, second, first, main 순으로 지워지며, main 함수까지 모두 완료 시 호출 스택은 비어짐

  • 호출 스택 & 태스크 큐 & 백그라운드
    • 태스크 큐(콜백 큐): 이벤트가 발생 후 호출되어야 할 콜백 함수들이 기다리는 공간
    • 백그라운드: 1) 타이머, 2) I/O 작업 콜백, 3) 이벤트 리스너 들이 대기하는 곳
function run() {
   console.log('3초 후 실행');
}
console.log('시작');
setTimeout(run, 3000);
console.log('끝');
시작
끝
3초 후 실행

호출 스택에 쌓이는 순서

  1. main이 호출 스택에 들어감
  2. setTimeout 함수가 호출 스택에 들어감

호출 스택 실행 순서

  1. setTimeout 실행
  2. 타이머와 함께 run callBack을 백그라운드로 보냄 (호출 스택에서 setTimeout 삭제)
  3. 호출 스택에서 main 삭제
  4. 백그라운드는 3초를 세고 run 함수를 테스크 큐로 보냄
  5. (호출스택이 비어있으므로) 태스크 큐에서 함수를 하나씩 가져옴
  6. 호출 스택에 가져온 함수를 실행

만약에 호출 스택에 함수가 굉장히 많아서 3초후에도 호출 스택에 실행할 함수가 남아있다면, run 함수는 호출 스택에 그만큼 더 늦게 올라오고 3초가 지난 후에도 실행되지 않을 수 있음
⇒ setTimeout의 시간이 정확하지 않을 수도 있는 이유!

논블로킹 I/O

논블로킹: 이전 작업이 완료될 때까지 멈추지 않고 다음 작업을 수행하는 것

블로킹보다 논블로킹 방식에서 같은 작업을 더 짧은 시간에 처리

but. 싱글 스레드라는 한계로 인해 JavaScript의 모든 코드가 이 방식으로 시간적 이득을 볼 수 없음

  • Node Process & I/O 작업이 주로 시간적 이득을 봄

I/O
입력(Input) & 출력(Output)을 의미
예시: 파일 시스템 접근(파일 읽기, 쓰기, 폴더 만들기 등), 네트워크 요청 작업

블로킹 - 논블로킹 & 동기 - 비동기
엄연히 따지면 다른 개념이지만, 동기-블로킹, 비동기-논블로킹이 유사한 관계라고 볼 수 있음

  • 블로킹 vs 논블로킹 코드 비교
    - 블로킹 방식
function longRunningTask() {
	// 오래 걸리는 작업
	console.log('작업 끝');
}
console.log('시작');
longRunningTask();
console.log('다음 작업');
시작
작업 끝
다음 작업

longRunningTask 함수가 호출되면,
이 작업이 완료되기 전까지 console.log('다음 작업')이 호출되지 않음

  • 논블로킹 방식
function longRunningTask() {
// 오래 걸리는 작업
	console.log('작업 끝');
}
console.log('시작');
setTimeout(longRunningTask, 0);
console.log('다음 작업');
시작
다음 작업
작업 끝

setTimeout을 통해 콜백 함수(longRunningTask)가 태스크 큐로 보내짐

다음 작업이 먼저 실행된 후 오래걸리는 작업이 완료됨

setTimeout(콜백, 0)

  • 코드를 논블로킹으로 만들기 위해 사용하는 기법 중 하나
  • 밀리초를 0으로 설정하더라도 바로 실행되지 않고 기본적인 지연시간 이후에 실행됨
    (HTML5 브라우저는 4ms, Node는 1ms 의 지연시간이 있음)

싱글 스레드

주어진 작업을 스레드 하나로 혼자 처리해야함

Thread: 컴퓨터 작업을 처리할 수 있는 일손

Multi-Thread: 여러 개의 스레드가 일을 나눠서 처리할 수 있음

  • JavaScript, Node는 싱글 스레드

    한 번에 한 가지 일만 처리하므로 어떤 작업에서 블로킹이 발생하면, 다음 일을 처리하지 못함

Multi Thread가 Single Thread 보다 나은가? No.
한 음식점에 점원이 한 명 - 손님이 여러 명일 때 (싱글 스레드)

  • 싱글스레드 - 블로킹 모델
    한 명의 손님에 대한 주문 - 요리 - 서빙을 모두 마쳐야 다음 손님에 대한 응대를 시작
  • 싱글스레드 - 논블로킹 모델 (Node 방식)
    한 명의 손님에 대한 주문 - 요리하는 중에 다른 손님에 대한 주문 - 요리,
    요리가 완료되면 완료되는 순서로 손님에게 서빙 (주문한 순서 ≠ 서빙한 순서일 수도)
    장점: 혼자서 많은 일을 처리
    단점: 점원 한 명에게 문제가 생기면 크리티컬한 문제 발생

한 음식점에 점원이 여러 명, 손님이 여러 명일 때 (멀티 스레드)

  • 멀티스레드 - 블로킹 모델
    손님 한 명당 점원이 한 명씩 맡아 주문을 받고 서빙
    장점: 손님 처리에 장점, 점원 한 명에게 문제가 생겨도 다른 점원으로 대체 가능
    단점**: 손님의 수가 늘어날수록 → 점원의 수 증가 // 손님 수가 감소하면 → 노는 점원이 발생

  • 프로세스 vs 스레드

프로세스(Process): 운영체제에서 할당하는 작업의 단위
(Node, Internet Browser 등은 개별적인 프로세스 → 프로세스 간 메모리 등 자원 공유는 일어나지 않음)

스레드(Thread): 프로세스 내에서 실행되는 흐름의 단위
(하나의 프로세스는 여러 개의 스레드로 구성되며, 스레드들은 부모 프로세스의 자원을 공유)

  • Node의 Thread - Process 구조

Node도 내부적으로는 여러 개의 Thread를 가지고 있지만, 우리가 제어할 수 있는건 하나뿐 ⇒ 싱글 스레드
Thread를 늘리는 대신 Process를 복사해 여러 작업을 동시에 처리하는 Multi Processing 방식을 채택
(JavaScript 언어 자체가 Single Thread 특성을 띄고 있기 때문에 Multi Processing 방식을 채택)

0개의 댓글