1 노드 시작하기

source: categories/study/nodejs/nodejs1.md

1.1 노드의 정의

1.1.1 공식 홈페이지의 설명

  • 노드를 서버라고 하시는 분들이 있는데 그것은 엄밀히말하면 틀린 말입니다.
    자바스크립트 엔진도 아닙니다.
    노드를 빌드한 엔진이 V8이고 이것은 자바스크립트 엔진입니다.
    1장은 이를 깨닫는 것이 중요합니다.

NodeJS는 크롬 V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임입니다.

  • 자바스크립트는 NodeJS 덕에 브라우저, HTML에만 종속되어있던 신세를 벗어날 수 있었습니다.
    NodeJS 이전에도 자바스크립트를 실행하려는 시도는 많았습니다.
    하지만 속도 문제를 벗어나지 못했습니다.
    그런데 크롬의 V8 엔진이 이를 해결해줬습니다.

  • 브라우저와 HTML에서 자바스크립트가 해방된 사실이 왜 중요하냐면, 해방됨으로써 자바스크립트 앱도 만들 수 있고 프로그램도 만들 수 있고 게임도 만들 수 있고, 아주 다양한 역할을 수행할 수 있게되었기 때문입니다.

  • 자바스크립트의 친구 언어로 타입스크립트가 있는데, 타입스크립트도 런타임이 있어야겠죠?
    타입스크립트 런타임으로 deno가 있습니다.
    node에서 앞뒤 글자가 바뀌어서 deno가 된 것인데 NodeJS 개발한 사람이 만든 것입니다.

1.1.2 노드는 서버가 아닌가요? 서버라는 말이 없네요.

  • 서버의 역할도 수행할 수 있는 자바스크립트 런타임
  • 노드로 자바스크립트로 작성된 서버를 실행할 수 있음
  • 서버 실행을 위해 필요한 http/https/http2 모듈을 제공

1.1.3 런타임

  • 노드: 자바스크립트 런타임

    • 런타임: 특정 언어로 만든 프로그램들을 실행할 수 있게 해주는 가상머신(크롬의 V8엔진 사용)의 상태
    • 노드: 자바스크립트로 만든 프로그램을 실행할 수 있게 해줌
    • 다른 런타임으로는 웹브라우저(크롬, 엣지, 사파리, 파이어폭스 등)가 있음
    • 노드 이전에도 자바스크립트 런타임을 만들기 위한 많은 시도가 있었음
    • But, 엔진 속도 문제로 실패

1.1.4 내부 구조

  • 내부: C, C++로 작성되어있음.
    보통 대부분의 이런 프로그램의 내부는 CC++로 작성되어있음. 그래야 빠르기 때문에.
    그럼 그냥 CC++로 하지 왜 자바스크립트란 언어를 만들었느냐. 그 이유는 생산성이 안좋기 때문.
    CC++은 좀 더 하드웨어에 가까운 난이도 있는 언어. 자바스크립트나 파이썬 등 이런 언어들은 조금 더 사람이 알아보기 쉬운 형식으로 만든 생산성을 높인 언어.
    어려운 기능도 알아서 처리해줌(메모리 관리 등). - 내부에서 C++이 알아서 처리해줌.

  • 2008년 V8 엔진 출시, 2009년 노드 프로젝트 시작

  • 노드는 V8과 libuv를 내부적으로 포함

    • V8 엔진: 오픈 소스 자바스크립트 엔진 -> 속도 문제 개선
    • libuv: 노드의 특성인 이벤트 기반, 논블로킹 I/O 모델을 구현한 라이브러리

  • libuv는 노드에서만 중요한 것이 아니라 자바스크립트에서도 중요합니다.
    비동기를 구현해주는 것인데, 노드가 뜬 이유, 자바스크립트가 뜬 이유가 싱글 스레드이면서 비동기인 모델, 프로그램 자체가 그렇게 작동합니다.
    싱글 스레드 + 비동기 - 제가 나중에 설명은 하겠지만 이것이 엄청난 장점이라 인기가 확 많아졌습니다.
    자바에선 멀티스레딩하고 그랬는데, 이게 프로그래밍 난이도가 좀 어려워서 개발자들이 원하는 성능을 못내는 경우가 많았는데, 노드는 간단한 싱글스레드 비동기라는 모델을 채택해서 코딩 대충해도 엄청나게 빠른 성능을 이끌어낼 수 있는.. 초보들이 하기 쉽다는 거죠.

  • 자바도 원래는 고수들은 멀티스레드건 뭐건 코딩 잘 했는데 초보들이 엄청나게 헤맸습니다. 멀티 스레드 때문에.
    그런데 노드는 초보들마저 쉽게 비동기 프로그래밍을 할 수 있게 해주었다. 이렇게 보시면 되겠습니다.

1.2 노드의 특성

1.2.1 이벤트 기반

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

    • 이벤트의 예: 클릭, 네트워크 요청, 타이머 등
    • 이벤트 리스너: 이벤트를 등록하는 함수
    • 콜백 함수: 이벤트가 발생했을 때 실행될 함수

1.2.1.1 부연설명

  • 브라우저의 주소창에 주소를 입력하는 행위도 이벤트입니다.
    해당 주소를 입력할 때 이벤트 발생 - 그 후 해당 사이트를 불러오도록 브라우저 개발자들이 처리해놓은 것입니다.
    즉, 대부분의 프로그램들이 이벤트 기반입니다.
    사실 이벤트 기반은 노드의 특징이 아니라 대부분의 프로그램들이 이렇다고 보시면 되겠습니다.

1.2.2 논블로킹 I/O

  • 논블로킹: 오래 걸리는 함수를 백그라운드로 보내서 다음 코드가 먼저 실행되게하고, 나중에 오래 걸리는 함수를 실행

    • 논블로킹 방식 하에서 일부 코드는 백그라운드에서 병렬로 실행됨
    • 일부 코드: I/O 작업(파일시스템 접근, 네트워크 요청), 압축, 암호화 등
    • 나머지 코드는 블로킹 방식으로 실행됨
    • I/O 작업이 많을 때 노드 활용성이 극대화

1.2.2.1 부연설명

  • 사람들이 노드에서 가장 오해를 많이 하는 부분입니다.
    논블로킹을 "동시"라고 오해하시는 분들이 계신데 "동시"가 아닙니다.
    그리고 비슷한 단어로 동기/비동기 라는 것이 있어서 조금 헷갈리실 겁니다.

  • 좀 가볍게 말씀드리자면 노드는 블로킹이면서 동기, 논블로킹이면서 비동기 이 두가지만 있다고 생각하시면 됩니다.
    블로킹/논블로킹, 동기/비동기 이것은 서로 뜻이 다릅니다.
    그런데 노드에선 다행히도 동기면서 논블로킹인거랑 비동기면서 블로킹인 것은 없습니다.
    만들어낼려면 만들 수 있겠지만 많이 쓰이진 않고 대부분 다 동기이면서 블로킹, 비동기이면서 논블로킹입니다.

  • 그런데 여기서 많이 하는 오해가 비동기이면서 논블로킹일 때, 노드가 동시에 돌아간다, 프로그램이 동시에 돌아간다라고 오해를 하시는데, 노드에서 동시에 돌아간다라는 것을 구현하는 것은 매우 힘듭니다.
    사실상 일부를 빼곤 없다고 생각하시면 됩니다.
    동시로 돌아가는 일부만 외우시면 됩니다.

  • 노드에선 동기는 블로킹, 비동기는 논블로킹이라고 일단 생각하셔도 괜찮습니다. 둘이 짝이기 때문에.

  • 동기: 코드가 순서대로 실행된다.

  • 비동기: 코드가 순서대로 실행되지 않는다.

동기 실행인지 아닌지는 따로 아시면 됩니다.

  • 블로킹: 코드가 순서대로 실행된다.

  • 논블로킹: 코드가 순서대로 실행되지 않을 수도 있다.
    어떤 규칙을 따른다. 그 규칙이 실행 콘텍스트, 이벤트 루프에 대해 배울 때 나온다.
    그 두개를 배우면 논블로킹일 때 어떻게 돌아가는지 예측이 됩니다.
    이 내용에 대해선 뒤에서 다루도록 하겠습니다.

Tip

이 부분은 실제 코드를 보면서 이해하는게 좋습니다.
3강에서 비교해봅니다.


a. 동기/비동기의 개념을 학습하기 전에 알아야할 내용 미리보기

a.1 쓰레드 개념

PC 사용

  • 4코어 8쓰레드
  • 8코어 16쓰레드

쓰레드는 일을하는 녀석이다.
8쓰레드라는 개념은 일을하는 녀석이 8개라는 개념이다.
16쓰레드라는 개념은 일을하는 녀석이 16개라는 개념이다.

ex) 아이폰 11프로 - 6코어, 내부적으론 12개 이상의 쓰레드가 있다고함.

PC, Mobile엔 일을하는 녀석인 쓰레드가 여러개 있음.
그런데 우리는 계속 한개의 쓰레드에만 일을 시키고 있던 거임.
그러면 아래와 같은 생각이 들거임.

b. 동기/비동기의 개념에 대한 가장 직관적인 이해

b.1 동기/비동기

b.1.1 Synchronous(동기) VS Asynchronous(비동기)

b.1.1.1 비동기 개념

b.1.1.2 동기 개념

다시 말로 정리해보겠음

  • 비동기(Async): "안 기다린다."
  • 동기(Sync): "기다린다."

위를 조금 더 자세하게 표현하자면,

  • 비동기(Async): 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 안 기다리고 다음일을 진행한다.
    (안 기다려도 다음 작업을 생성할 수 있다.)

  • 동기(Sync): 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 기다렸다가 다음일을 진행한다.
    (기다렸다가 다음 작업을 생성할 수 있다.)

이런 비동기라는 개념이 일반적으로 필요한 이유는?

대부분은 서버와의 통신(네트워크 작업) 때문.
이런 네트워크 관련해서 공부하실 때 보통, 동기, 비동기 개념에 대해 접하실거임.
이 정도 이해하시면 동기, 비동기에 대해선 이해가 끝난거임.

동기, 비동기 핵심 keyword: return 을 바로 해주느냐 마느냐

b.1.2 Serial(직렬) queue VS Concurrent(동시) queue

b.1.2.1 직렬처리

b.1.2.2 동시처리

  • 직렬(Serial) 처리: 다른 한개의 쓰레드에서
  • 동시(Concurrent) 처리: 다른 여러개의 쓰레드에서

자세하게 말씀드리면

  • 직렬(Serial) 처리: (보통 메인에서) 분산처리 시킨 작업을 다른 한 개의 쓰레드에서 처리
  • 동시(Concurrent) 처리: (보통 메인에서) 분산처리 시킨 작업을 다른 여러개의 쓰레드에서 처리

분산처리 하려는 것이라면.. 무조건 동시(Concurrent) 처리가 좋아보이는 것 같은데..
직렬(Serial) 처리가 필요할까?

  • 직렬(Serial) 처리 : 순서가 중요한 작업을 처리할 때 사용
  • 동시(Concurrent) 처리 : 각자 독립적이지만(중요도나 작업의 성격 등) 유사한 여러개의 작업을 처리할 때 사용
b.1.2.3 실제 예시로 설명

비동기(Async)란 말과 동시(Concurrent)란 말이 같은 말인가?

완전히 다른 말임.
비동기란 말은 작업을 보내는 쓰레드에 관련된 개념임.
쓰레드1에서 다른 쓰레드로 보낸 작업을 기다릴지 말지에 관련된 이런 개념이 동기, 비동기에 대한 개념.

동시적 처리, 직렬처리 이런 말은 뭐냐면, 메인 쓰레드에서 다른 쓰레드로 작업을 보낼 때, 보내는 대상이 되는 쓰레드가 1개냐 아니면 여러개냐, 이런 개념을 말을 할 때 쓰는 개념임.

그렇기 때문에 비동기라는 말과 동시라는 말은 완전히 다르다는걸 개념적으로 아실 수 있을 것.

b.1.3 왜 동시성(Concurrency) 프로그래밍이 필요할까? (iOS앱 사례로 설명)

왜 동시성(분산처리)가 필요할까?
무거운 작업을 쓰레드 하나한테만 맡기면 앱이 버벅거리니깐.
네트워크 관련 일은 여러 쓰레드에서 하도록 만들어줘야됨.

  • 성능/반응성
  • 최적화

c. 자바스크립트 동기, 비동기, 블록, 논블록

c.1 동기 VS 비동기 (feat. blocking VS non-blocking)

c.1.1 동기(Synchronous) VS 비동기(Asynchronous)

네트워크 코드를 공부하면서 동기/비동기에 대해서 더 많이 접했던 것 같다.

c.1.1.1 동기(Synchronous)

  • Thread1이 작업을 시작 시키고, Task1이 끝날때까지 기다렸다 Task2를 시작한다.
  • 작업 요청을 했을 때 요청의 결과값(return)을 직접 받는 것이다.
  • 요청의 결과값이 return값과 동일하다.
  • 호출한 함수가 작업 완료를 신경 쓴다.
c.1.1.2 비동기(Asynchronous)

  • Thread1이 작업을 시작 시키고, 완료를 기다리지 않고, Thread1은 다른 일을 처리할 수 있다.
  • 작업 요청을 했을 때 요청의 결과값(return)을 간접적으로 받는 것이다.
  • 요청의 결과값이 return값과 다를 수 있다.
  • 해당 요청 작업은 별도의 스레드에서 실행하게 된다.
  • 콜백을 통한 처리가 비동기 처리라고 할 수 있다.
  • 호출된 함수(callback 함수)가 작업 완료를 신경 쓴다.

c.1.2 blocking vs non-blocking

blocking과 non-blocking은 주로 IO의 읽기, 쓰기에서 사용된다.

c.1.2.1 blocking
  • 요청한 작업을 마칠 때까지 계속 대기한다.
  • 즉시 리턴하지 않는다. (일을 못하게 막는다.)
  • return 값을 받아야 끝난다.
  • Thread 관점으로 본다면, 요청한 작업을 마칠 때까지 계속 대기하며 return 값을 받을 때까지 한 Thread를 계속 사용/대기 한다.
c.1.2.2 non-blocking
  • 요청한 작업을 즉시 마칠 수 없다면 즉시 return한다.
  • 즉시 return한다.
  • Thread 관점으로 본다면, 하나의 Thread가 여러 개의 IO를 처리 가능하다.

c.2 동기/비동기, blocking/non-blocking의 차이는?

사실 이렇게만 보면 동기랑 blocking이 비슷하고, 비동기랑 non-blocking이 비슷해보인다.
동기/비동기, blocking/non-blocking 두 그룹의 차이는 관심사가 다르다.

c.2.1 blocking/non-blocking

이 그룹은 호출되는 함수가 바로 return하느냐 마느냐가 관심사이다.

호출된 함수가 바로 return해서 호출한 함수에게 제어권을 넘겨주고
호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 non-blocking이다.

호출된 함수가 자신의 작업을 모두 마칠 때까지
호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 blocking이다.

c.2.2 동기/비동기

이 그룹은 호출되는 함수의 작업 완료 여부를 누가 신경쓰느냐가 관심사이다.

호출되는 함수에게 callback을 전달해서 호출되는 함수의 작업이 완료되면
호출되는 함수가 전달받은 callback을 실행하고, 호출한 함수는 작업 완료 여부를 신경쓰지 않는다면 비동기이다.

호출하는 함수가 호출되는 함수의 작업 완료 후 return을 기다리거나
호출되는 함수로부터 바로 return 받더라도 작업 완료 여부를 호출한 함수 스스로 확인하며 신경 쓴다면 동기이다.

c.3 동기/비동기, blocking/non-blocking 조합

동기/비동기, blocking/non-blocking에 대해 공부하다보면 아래와 같은 그림과 자주 마주치게 된다.

c.3.1 blocking + Synchronous, non-blocking + Asynchronous

c.3.1.1 blocking + Synchronous

결과가 처리되어 나올때까지 기다렸다가 return 값으로 결과를 전달한다.

  • 동기: 호출된 함수의 작업완료여부를 직접 신경씀
  • 블록: 호출된 함수가 완료될 때까지 return 안함. 완료되면 return함
c.3.1.2 non-blocking + Asynchronous

작업 요청을 받아서 별도의 프로세서에서 진행하게 하고 바로 return(작업 끝)한다.
결과는 별도의 작업 후 간접적으로 전달(callback)한다.

  • 비동기: 호출된 함수의 작업완료여부를 신경안씀
  • 논블록: 호출된 함수가 호출되자마자 바로 return함. 완료되던말던 바로 return.
c.3.1.3 non-blocking + Synchronous

결과가 없다면 바로 return한다.
결과가 있으면 바로 결과를 return 한다.
(결과가 생길때까지 계속 완료 되었는지 확인)

  • 동기: 호출된 함수의 작업완료여부를 직접 신경씀
  • 논블록: 호출된 함수가 호출되자마자 바로 return함. 완료되던말던 바로 return.
c.3.1.4 blocking + Asynchronous

호출되는 함수가 바로 return하지 않고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않는다.
(이 조합은 사실 이점이 없어서 일부러 이 방식을 사용하진 않는다고 한다.)
(의도하지 않게 blocking+Async로 동작하는 경우가 있다고는 한다. 이는 non-blocking+Async를 추구하다 의도가 변질되어버림… 대표적으로 Node.js + MySQL 조합이라고 한다.)

  • 비동기: 호출된 함수의 작업완료여부를 신경안씀
  • 블록: 호출된 함수가 완료될 때까지 return 안함. 완료되면 return함

c.4 예시

상황: 급하게 알아야 하는 답을 누군가에게 물어봐야하는 상황

  • 전화로 물어봐서 즉답을 얻는다. = 동기 요청처리
  • 이메일로 물어보고 메일 송신을 완료(return)했지만 답은 언제 올지 모른다. = 비동기 요청처리
  • 전화를 했는데 상대방이 너무 바빠 전화를 받지 않음 전화를 받을때까지 계속 대기 = 동기 + 블록킹
  • 전화를 했는데 안 받음 끊었다가 나중에 다시 전화함 계속 반복했다가 어느 순간에 받아서 답을 얻음 = 동기 + 논블록킹

c.5 최종정리

  1. 동기/비동기: 호출된 함수의 작업완료여부를 호출한 함수가 체크하느냐, 아니면 같이 전달한 callback 함수가 알아서하느냐.

    • 동기: 호출된 함수의 작업완료여부를 호출한 함수가 직접 체크하면 동기
    • 비동기: 호출된 함수의 작업완료여부를 호출한 함수가 체크 안하면 비동기
  2. 블록/논블록: 호출된 함수가 바로 return하는지 마는지.

    • 블록: 호출된 함수가 다 완료된 후 return하면 블록 - 제어권을 호출된 함수가 다 완료될 때까지 안넘겨주므로
    • 논블록: 호출된 함수가 완료되던 안되던 바로 return해서 제어권을 호출한 함수로 넘기면 논블록
  3. 동시성(동시적)처리/직렬처리: 메인스레드가 다른 스레드로 작업을 보낼 때, 보내는 대상이되는 스레드가 1개냐 아니면 여러개냐

    • 동시성처리: 여러개 스레드로 보내면 동시적 처리
    • 직렬처리: 1개의 스레드로 보내면 직렬처리 (처리 순서가 필요할 때 직렬처리 사용)
NodeJS는, 자바스크립트는 

1. 비동기이면서 논블록
2. 동기이면서 블록

이 두가지 경우가 거의 대부분이다.
아직 이 개념이 100% 와닿진않지만.. 코드적으로 동기/비동기, 블록/논블록인 상황들을 구체적으로 봐야 좀 더 이해가 잘 갈 것 같다.. 
그래도 예전에비해선 많이 이해가간다.

1.2.3 프로세스 VS 스레드

  • 프로세스와 스레드

    • 프로세스: 운영체제에서 할당하는 작업의 단위, 프로세스 간 자원 공유X
    • 스레드: 프로세스 내에서 실행되는 작업의 단위, 부모 프로세스 자원 공유
  • 노드 프로세스는 멀티 스레드이지만 직접 다룰 수 있는 스레드는 하나이기 때문에 싱글 스레드라고 표현

  • 노드는 주로 멀티 스레드 대신 멀티 프로세스 활용

  • 노드는 14버전부터 멀티 스레드 사용 가능

1.2.3.1 부연설명

  • 싱글 스레드를 하려면 프로세스와 스레드에 대해 알아야합니다.
    기본적으로 여러분들이 프로그램을 실행할 때마다 프로세스가 하나씩 더 생긴다고 보면 됩니다. (기본적으로)
    프로세스가 여러개 생성되는 애들도 있는데, 걔네들은 다른 용도를 위해서 그런거니까, 기본적으론 프로그램 하나 실행하면 프로세스가 하나 생성된다고 보시면 됩니다.
    여러분들이 노드에서 서버 코드를 작성해서 노드를 통해서 실행을 해도 프로세스가 하나 생성된다, 라고 생각하시면 됩니다.

    크롬을 생각해봅시다.
    크롬을 생각하면 프로세스가 하나가 생성되겠죠?
    그런데 크롬 안에서 Tab 여러개를 띄울 수 있죠?
    그 Tab들이 마치 각각의 프로그램마냥 돌아가죠?
    이때 각 Tab들을 스레드라고 생각하시면 됩니다.

    실제 크롬은 각 창을 프로세스로 띄웁니다.
    여기서는 그냥 비유로 봐주세요.

  • 노드는 싱글 스레드다? 그게 무슨 뜻이냐면, 노드를 실행하면 프로세스가 생성되겠죠?
    프로세스가 생성되는데 그 안에 스레드를 하나밖에 못만드는 겁니다.
    여기서도 많은 오해가 있는데, 노드는 싱글 스레드가 아닙니다.
    노드를 실행하시고 작업관리자로 검사를 하실 수 있는데,(작업관리자:ctrl+shift+esc) 프로세스와 스레드 검사하면 스레드가 여러개로 뜹니다.
    그러면 지금까지 알고 있었던 사실과 달라 혼란스러우실 수도 있을겁니다.

  • 노드 분명히 싱글 스레드라고 했는데?
    그게 노드를 실행할 땐 프로세스 안에 스레드가 여러개 뜹니다.
    여러개가 뜨는데 그 중에서 여러분들은 하나만 컨트롤할 수 있습니다.
    그래서 노드를 싱글 스레드라고 하는 겁니다.
    노드는 원래는 멀티 스레드입니다.

  • 그리고 노드14버전에 들어오면서 여러분들이 직접 멀티 스레드를 다룰 수 있게 되었습니다.
    노드는 원래 멀티스레드였지만 자바스크립트로 코딩하면 자바스크립트로 코딩한 것이 스레드를 하나밖에 차지 안하기 때문에 싱글 스레드라고 했던 것이고 노드 14버전부턴 여러분들이 원한다면 멀티 스레드를 사용하실 수 있습니다.

  • 멀티 스레드를 하면 뭐가 좋을까요?
    멀티 스레드를 하면 당연히 동시에 여러가지를 할 수 있으니까 좋습니다.
    크롬 Tab에 페이스북, 인스타그램, 트위터를 켜놓으면 각각 알아서 알림이 뜹니다.
    하지만 싱글 스레드라면 현재 Tab을 닫고 페이스북으로 들어가서 알림이 왔는지 확인하고 다시 페이스북을 닫고 인스타가서 알림이 왔는지 확인해야됩니다.

  • 그러면 노드도 처음부터 멀티스레드하지 왜 싱글스레드로 했어요?
    멀티스레드 단점: 코딩이 너무 어렵습니다.
    멀티스레드라는 것을 이해하기 힘들어서 "아 난 한가지 일만 잘할래" 그래서 싱글 스레드 방식으로 간겁니다.
    그래서 쉽고 좋았는데, 그래도 좀 아쉽잖아요?
    안하는 거랑 못하는 거랑은 다른데, 노드는 멀티 스레드를 못했습니다.
    그런데 이제 노드 14버전에서 멀티 스레드를 할 수 있게 가능성을 열어준겁니다.

    아직까지는 많이 쓰이는 것 같지는 않은데, 아예 못하는 것보단 할 수 있게 가능성을 열어준게 큰 발전인거죠.

  • 노드가 멀티스레드고 개발자가 컨트롤할 수 있는 스레드가 하나라면 나머지 스레드는 뭘하고있나요?
    예를 들어 노드를 실행하면 스레드가 4개가 생기는데, 사람이 컨트롤할 수 있는 스레드는 한 개, 그럼 나머지 3개는 뭘하고 있을까요?
    나머지 3개는 코드를 동시에 돌릴 준비를 하고 있습니다.

    앞서 제가 논블로킹에서 코드가 동시에 안돌아간다라고 했잖아요?
    동시에 돌아가려면 어떠한 조건을 만족시켜야된다. 이렇게 말씀을 드렸는데, 그 특정한 조건이 만족되기 전까진 그냥 대기를 하고 있는겁니다.
    특정한 조건이 만족되면 나머지 스레드들을 활용해서 동시에 돌려주는겁니다.

    진짜 노드가 아예 싱글스레드였다면 "동시"라는 개념이 나올수가 없었을겁니다.
    하나의 일을 하는데 다른 일을 할수가 없죠.
    분명 스레드가 다른 것이 있었으니까 "동시"에 할 수 있었던 겁니다.

1.2.4 싱글 스레드

  • 싱글 스레드라 주어진 일을 하나밖에 처리하지 못함

    • 블로킹이 발생하는 경우 나머지 작업은 모두 대기해야함 -> 비효율 발생
  • 주방에 비유(점원: 스레드, 주문: 요청, 서빙: 응답)

1.2.4.1 부연설명

  • 스레드 하나는 CPU의 코어 하나를 잡아먹습니다.
    보통 요즘 8코어/16코어/32코어 등등 코어가 존재하는데, 만약 CPU가 32코어(비쌈)라면 그 중에서 딱 1개 사용하고 나머지 31개는 놀고있는 겁니다.
    즉, 사실 싱글 스레드는 그렇게 효율적인 구조는 아닙니다.(블로킹이 발생하는 경우 나머지 작업은 모두 대기해야되기 때문)

1.2.5 멀티 스레드 모델과의 비교

  • 싱글 스레드 모델은 에러를 처리하지 못하는 경우 멈춤

    • 프로그래밍 난이도도 쉽고, CPU, 메모리 자원 적게 사용
  • 멀티 스레드 모델은 에러 발생시 새로운 스레드를 생성하여 극복

    • 단, 새로운 스레드 생성이나 놀고있는 스레드 처리에 비용 발생
    • 프로그래밍 난이도 어려움
    • 스레드 수만큼 자원을 많이 사용함
  • 점원: 스레드, 주문: 요청, 서빙: 응답

1.2.5.1 부연설명

  • 싱글 스레드는 위에 점원 한명만 일을 하는 것입니다.
    나머지 두명의 점원은 놀고있습니다.
    그럼 점원 한명만 일을 엄청하고 앓아 눕겠죠?
    이것이 노드의 방식입니다.

  • 위의 그림처럼 점원 한명한명이 일하는 방식이 멀티 스레드 방식.
    딱 봐도 구조는 멀티 스레드가 효율적인 것처럼 보입니다.
    단, 점원을 3명쓰니까 인건비가 3명이나 나가죠?
    아까 멀티 스레드 코딩하기가 어렵다고 그랬죠?
    하지만, 그렇다고 기존 싱글 스레드처럼하자니 점원도 힘들고 고객들도 대기해버리는 상태가 되는거죠.

    그래서 타협을 한 방식이 다음과 같은 노드의 방식입니다.

1.2.6 싱글 스레드

  • 대신 논블로킹 모델을 채택하여 일부 코드(I/O)를 백그라운드(다른 프로세서)에서 실행 가능

    • 요청을 먼저 받고, 완료될 때 응답함
    • I/O 관련 코드가 아닌 경우 싱글 스레드, 블로킹 모델과 같아짐

1.2.6.1 부연설명

  • 일단 주문만 순서대로 받아놓고 주방에다 다 보낸 다음에 요리가 완료되는대로 고객한테 주는 방식입니다.
    하지만 이것도 한계가 보이죠?
    주문이 한번에 쏠리면 점원이 힘들 것이고, 주문이 너무 많이 왔을 때, 주방에서 주방장이 처리하다가 기절할 수도 있겠죠.
    그래서 싱글 스레드였을 때 노드는 점원, 주방장 관리를 잘해야됩니다.
    점원, 주방장이 지쳐 쓰러지는 순간 서비스가 망하거든요.

  • 그래서 많이 했던 방식이 멀티 프로세싱이라고 해서
    (점원(스레드)이 하나인 체인점(노드 프로세스)을 여러개 -> 멀티 프로세싱)
    체인점을 내는 겁니다.
    체인점을 내서 16명의 고객이 있으면 그 고객을 16개 체인점으로 분산을 해주는 것, 이런 방식을 많이 써서 극복을 했었습니다.

  • 멀티 스레드는 이상적인 방식.
    멀티 스레드로 코딩하기란 매우 어렵습니다.

  • 멀티 스레드로하면 비동기 처리가 필요없나요?
    라고 하셨는데, 멀티 스레드를 해도 비동기 처리는 계속 해야됩니다.
    멀티 스레드를 안하려고 노드를 하는 거에요.
    멀티 스레드가 너무 어려운데 프로그램은 효율적으로 돌리고 싶어서 노드를 하는 거거든요?

    그런데 아예 멀티 스레드를 못하게하는 것보단 그래도 하게 해주는게 낫지 않겠냐,해서 노드 14버전에서 멀티 스레드를 추가만해준거지 노드에서 주력이 멀티스레드가 될 일은 없습니다.
    없으니까 아쉬워서 추가를 해준거지 앞으로 싱글스레드 사용하지말고 멀티스레드를 사용하세요라는 뜻에서 14버전에서 넣은 것이 아닙니다.
    그래서 멀티 스레드를 배우셔도 실무에선 사용할 일이 거의 없을거에요.
    그냥 이런 것이 생겼구나, 라는 것만 알아두시면 되고 노드의 핵심은 싱글 스레드를 어떻게 효율적으로 관리하냐이기 때문에 싱글 스레드를 잘 다루는 것을 중점으로 익히시면 됩니다.

1.2.7 멀티 스레드의 활용

  • 노드 14버전

    • 멀티 스레드를 사용할 수 있도록 worker_threads 모듈 도입
    • CPU를 많이 사용하는 작업인 경우에 활용 가능
    • 멀티 프로세싱만 가능했던 아쉬움을 달래줌
      원래는 체인점 내는 것만 가능했는데, 이제는 하나의 가게에서 여러 직원들을 두는 방법이 가능하게 됐다.
      여튼 멀티스레드가 메인이 될 일은 없다는 것.

1.3 노드의 역할

1.3.1 서버로서의 노드 1

  • 서버: 네트워크를 통해 클라이언트에 정보나 서비스를 제공하는 컴퓨터 또는 프로그램
  • 클라이언트: 서버에 요청을 보내는 주체(브라우저, 데스크탑 프로그램, 모바일 앱, 다른 서버에 요청을 보내는 서버)
  • 예시

    • 브라우저(클라이언트, 요청)가 길벗 웹사이트(서버, 응답)에 접속
    • 핸드폰(클라이언트)을 통해 앱스토어(서버)에서 앱 다운로드
  • 노드 !== 서버
  • But, 노드는 서버를 구성할 수 있게 하는 모듈(4장에서 설명)을 제공

1.3.2 서버로서의 노드 2

노드는 서버는 아니지만 서버로 사용할 수 있습니다.
저희가 자바스크립트로 서버를 만드는 코딩을 하면 노드가 그것을 실행을 해줘서, "이제 니 컴퓨터는 서버야" 이러면서 제 컴퓨터에 서버를 실행해줍니다.
제 컴퓨터가 노드 덕분에 서버가 되는 건데, 노드로만든 서버의 장단점은 노드의 장단점/자바스크립트의 장단점과 크게 다르지 않습니다.

  • 노드 서버의 장단점

  • 멀티 스레드 방식에 비해 컴퓨터 자원을 적게 사용하는 것이 장점이나 반대로 자원을 많이 사용하고 싶을 경우엔 단점입니다.
  • I/O(Input/Output) - I/O 작업이란 요청받고 응답주고 파일을 읽고 읽은 내용을 전달해주고 이런 것들을 뜻합니다. 이런 것들을 매우 잘합니다.
    하지만 CPU 작업이 많은 것. - 한번 요청왔는데 점원과 주방장을 엄청나게 고통스럽게 만들고 그럴 경우. 진상 손님이오면 노드서버는 정신을 못차림.
    주로 이미지 리사이징, 암호화 이런 것들이 있습니다. 알고리즘 문제 막 푸는 작업.
    그래서 이런 것들을 처리하지 못하니까 멀티 스레드를 열어준겁니다.
    그걸 위해 멀티 스레드를 열어준거지 아예 처음부터 멀티스레드를 하라고 멀티스레드 기능을 추가해준 것이 아닙니다.
    기본은 항상 싱글 스레드입니다.
  • 멀티 스레드보다 쉽고 웹 서버도 열기쉽게 코딩을 다 제공해줍니다.
    단점은 위에서 말했듯이 점원이 한명이므로 쓰러지지 않게 관리를 잘 해야되고, 서버 규모가 커지면 서버를 관리하기 어렵습니다.
    그런데 이것은 노드의 단점일 뿐만아니라 대부분의 서버가 서버 규모가 커지면 관리하기가 어렵습니다.(노드만의 단점이라고 보긴 좀 어려움)
  • 제가 생각하는 가장 큰 장점이 바로 자바스크립트를 사용한다는 것입니다.
    자바스크립트를 사용하는 개발자가 세계에서 거의 1위거든요?
    실제로 자바스크립트를 하는 프로그래머들이 제일 많습니다.
    그 말인 즉슨 커뮤니티가 크다, 그리고 시장에서 자바스크립트가 사라질일이 없다, 기술 자체가 안정적이다.
    노드는 없어지지 않아요.
    노드를 없애려면 자바스크립트로된 무언가가 새로 나와야지 노드를 이길 수 있지, 자바의 스프링, 루비온레일즈, 쟝고 이런 애들이 노드를 없애는 일은 없을겁니다.
  • 그럼 노드의 적은 누구냐
    deno입니다.
    deno가 노드를 없앨 수 있지 다른 것들은 불가능하다고 보시면 됩니다.
  • 프로그래밍할 때 JSON이라는 데이터 규격을 많이 쓰는데, 자바에서도 JSON 사용하고, PHP에서도 JSON 사용하고, C#에서도 JSON을 사용합니다.
    자바스크립트에서도 당연히 JSON을 사용합니다.(JSON이 자바스크립트이니깐)
    그래서 다른 언어들을 JSON을 자기네 언어로 변환하려고 그런 것들을 다 개발해서 넣어놨는데, 노드는 변환을 할 필요가 없죠?
    JSON이 자바스크립트이기 때문에.
    그냥 실행하면 돌아가는겁니다.
  • 단점, 성능이 어중간하다.
    극단적인 성능을 요구하는 것들이 있죠? 머신러닝이라던지 비트코인 채굴, 게임.
    이런 것들은 서버로 노드를 사용하기보다는 C++ 이런걸로 서버를 만드는 것이 좋습니다.
    그런데 그렇다고 아예 안 쓰이는 것은 아닙니다.

    Tip

    아까 노드가 빠르다고 했지만, 진짜 성능을 원한다면 더 빠른게 많습니다.

    적재적소에 사용하셔야됩니다.
    노드보다 성능 좋은 서버로 Rust로 만든 서버라던지 Go로 만든 서버라던지.
    서버의 성능이 크게 요구되지 않는 곳이라면 노드가 장점이 아주 많습니다.

  • CPU 작업을 위해 AWS Lambda나 Google Cloud Functions같은 별도 서비스 사용
  • 페이팔, 넷플릭스, 나사, 월마트, 링크드인, 우버 등에서 메인 또는 서브 서버로 사용

노드도 마이크로 서비스 구축 가능합니다. 서버라는 것은 사실 언어는 그렇게 중요하지 않아요. 간혹 PHP를 무시하시는 분이 있는데, PHP로도 모든 서비스를 다 만들 수 있어요. 그래서 서버쪽이나 서비스쪽은 언어가 크게 중요하지 않은데, 어떨 때 중요하냐.

그 언어의 특성을 모두 다 활용했을 때.

언어의 특성을 모두 다 활용할 때, 그때 뭐가오냐면 그 언어의 한계가 다가와요.
위에서 말씀드렸따시피 노드, - 어중간한 성능
이거는 대부분의 언어가 성능이 어중간하거든요?
C, C++, Rust 이런 애들 빼고는 다 성능이 어중간해서, 결국 그 언어로 할 수 있는 모든 것을 끌어냈는데도 성능이 부족하다. 그럴 때 언어를 바꿔야되는거지 성능문제가 없으면 웬만하면 언어를 바꿀 필요는 없습니다.
왜냐하면 모든 언어로 모든 서비스를 다 만들 수 있기 때문에.
PHP로도 머신러닝 할 수 있고 자바스크립트로도 머신러닝 할 수 있습니다.
왜 안하냐, 안하는 이유는 다른 이유가 있는겁니다.
아예 못해서 안하는게 아니라 더 나은게 있어서 안하는거지 못해서 안하는게 아닙니다.

1.3.3 서버 외의 노드

  • 자바스크립트 런타임이기 때문에 용도가 서버에만 한정되지 않음
  • 웹, 모바일, 데스크탑 애플리케이션에도 사용

    • 웹 프레임워크: Angular, React, Vue, Meteor 등
    • 모바일 앱 프레임워크: React Native
      자바랑 스위프트 안 배우고 싶어, 자바스크립트로 앱 만들래!
      그래서 React Native 만들어냈고,
    • 데스크탑 개발 도구: Electron(Atom, Slack, VSCode, Discord 등 제작)
      나 C#, C++, C 이런 마이크로소프트 언어로 안 만들래! 난 자바스크립트로 만들거야!
      그래서 Electron 등장
  • 위 프레임워크가 노드 기반으로 동작함

1.4 노드, VS Code 설치하기

1.4.1 노드 설치하기

  • 윈도(10 기준), 맥(카탈리나 기준)

    • https://nodejs.org 접속
    • LTS 버전인 14버전 설치
    • LTS는 안정된 버전, Current는 최신 버전(실험적)

1.4.1.1 부연설명

  • https://nodejs.org/en/about/releases/

    각 버전마다 3년동안 안정적으로 사용할 수 있다는 뜻입니다.(initial release ~ end of life)
    지금 안정적인 버전은 14버전이라는 뜻입니다.
    그럼 15 버전은 뭐냐.
    안정적인 버전은 급격한 변화 없이 버그패치, 보안패치만 해주고있고 15버전에서 다음 노드에서 사용할 신 기능들을 넣고 있는겁니다.

    여러분들이 실무를 하실 땐 LTS를 사용하시는 것이 정신건강에 좋을 것이고 공부하시는 입장이라면 최신 버전으로 빠르게 신기술을 습득하시는 것이 좋을것입니다.

  • 노드 설치시 주의사항

    위의 항목을 체크해주시면 위와 같이 파워쉘이 뜹니다.
    이것은 파이썬도 설치하고 C 관련된 것들도 설치하는 것인데, 이게 노드가 아무래도 자바스크립트이다보니까 성능이 어중간하다고 했잖아요?
    성능이 어중간하면 아까 말씀드렸던 이미지 리사이징 그리고 암호화 이런거 어떻게하느냐.
    방법은 두가지입니다.

    1. 자바스크립트로 느리게하거나
    2. C++로 엄청 빠르게 만들어서 그 결과물만 자바스크립트로 가져오거나

    그럼 당연히 2번째 방법으로 하겠죠?
    귀찮은 사람들은 1번으로 하겠지만 성능 중요한 사람들은 2번으로 할겁니다.
    자바스크립트가 C한테 말을 걸 수 있습니다.
    "C야, 너가 암호화 대신해주고 결과물만 나한테 넘겨줘."

    이렇게 노드랑 C랑 연결할 때, 위와 같은 설치가 필요합니다. 파이썬도 같이 설치해야되고 Chocolatey 이런 것도 같이 설치하고.

    그래서 이거를 설치안하면 나중에 저희가 회원가입 만들 때 암호화를 하거든요?
    그때 암호화가 설치가 안될거에요.
    왜냐, C도 없고 파이썬도 없기 때문에.
    그때 노드 지웠다가 다시 설치하고 그래야하니깐 처음부터 잘 설치하시면 편합니다.

    Mac은 좀 개발자 친화적이라 위와 같은 설치가 굳이 필요없을 겁니다.
    위와 같은 것을 미리 다 설치해주기 때문입니다.

  • 프로그램할 때 한글 폴더는 사용자제.
    한글로 되어있는 폴더 사용했다가 아주 큰 고통을 받는 수가 있음.
    해당 폴더 우클릭 - 속성으로 위치에 있는 경로에 한글이 들어가있으면 안됨
    특히 사용자 계정명이 한글이면 더 심한 고통을 겪을 수도..

  • 리눅스에서 설치할 때(우분투 18 LTS 기준)

    • 터미널에 아래 코드 순서대로 입력

      sudo apt-get update
      sudo apt-get install -y build-essential
      sudo apt-get install -y curl
      curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash --
      sudo apt-get install -y nodejs
      

1.4.2 노드 설치 확인

  • 설치 완료 후 윈도, 맥, 리눅스 모두 명령 프롬프트나 터미널 실행 후 다음 명령어 입력

    node -v
    
    npm -v
    
  • 버전은 다를 수 있지만 버전이 뜨면 설치 성공

    • npm 버전을 업데이트하려면 다음 명령어 입력
    • 맥과 리눅스는 명령어 앞에 sudo 필요

      npm install -g npm
      npm i -g npm
      

1.5 Q&A

  1. 웹스톰이 뛰어난 점은 무엇인가요?
  • 웹스톰은 사실 대규모 프로젝트에 안가보시면 몰라요.
    프로그램 규모가 적은 작업을 하시면 웹스톰을 사용하셔도 큰 이점은 못 느끼실 수도 있습니다.
    폴더랑 파일이 수백개만 넘어가도 웹스톰으로 하시는게 편한게
    예를 들어, 어떤 변수를 다른 파일로 옮긴다고 했을 때, 하필 그 변수를 다른 수많은 파일에서도 import 해서 사용하고 있었어요.
    그러면 그 변수를 import하고있는 파일들을 저희가 직접 찾아서 수정을 해줘야되는데, 웹스톰은 알아서 그 변수가 어디에 사용되었는지를 파악해서 알아서 옮겨줍니다.
    require이나 import를 스스로 파악해서 알아서 옮겨줍니다.

    웹스톰은 한마디로 표현하자면 리팩토링의 신이거든요?
    그런데 리펙토링을 안하는 곳에선 거의 기능을 사용하질 않죠.
    리펙토링을 언제 많이하냐.
    리펙토링은 보통 대규모 회사에서 많이 합니다.
    아니면 코드베이스가 크거나.

  1. 노드 중급 고급으로 공부하려면 어떤걸 추천하시나요?
  • 노드 중급부터는 실무를 많이 하시면 됩니다.
    초보는 언어 자체에 대한 이해도도 낮을 때.
    중수는 서버나 네트워크 등 이론에 대한 이해도가 낮을 때.
    이 둘을 모두 통달한 고수가 될 때, 언어에 대한 한계가 느껴짐.
    그런 사람들이 언어를 새로 만듦
    언어를 만드는 사람들은 그 언어로 한계까지 모든걸 다 해보고나서 도저히 그 언어로는 극복이 안되는 것이 있다는 것을 느꼈을 때 새 언어를 만듦.
  1. 정리
  • 이벤트 기반: 이건 대부분의 프로그램에 속하는 것
  • 논블로킹
    블로킹은 순서대로 실행되고 논블로킹은 순서대로 실행되지 않는다.
    그런데 프로그래밍에 랜덤이란 것은 거의 없다. 코드가 랜덤으로 실행되진 않고 논블로킹이라고 하면 순서대로 실행되진 않는데 그것마저도 규칙이 있다.
    순서대로 실행되진 않지만 그 순서대로 실행되지 않는 것에 대한 규칙 - 그것이 이벤트 루프
    그래서 이벤트 루프를 아셔야됩니다.
  • 동기가 순서대로 실행되는 것은 실행 콘텍스트. 즉, 동기를 이해하시기 위해선 실행 콘텍스트를 이해하셔야되고
    비동기를 이해하시기 위해선 이벤트 루프를 아셔야됩니다.
    이 두개를 아시면 자바스크립트 이해를 하실 때 많은 도움이됩니다.
  • 프로세스 VS 스레드
    싱글스레드 : 일손이 하나
    멀티스레드 : 효율적이지만 코딩하기가 너무 어렵고 처음에 자원도 많이 잡아먹고
    싱글스레드 프로그래머, 멀티스레드 프로그래머 둘 다 고수라면 당연히 멀티스레드 프로그래머가 더 효율적인 코드를 짜겠지만
    둘다 초보라면 싱글스레드 프로그래머는 완성은 시키는데 멀티스레드 프로그래머는 완성조차 못시킬 가능성이 있다.
  • 다시한번, 자바스크립트에서 정말 중요한 개념, 실행 콘텍스트와 이벤트 루프
    this와 scope는 실행 콘텍스트 안에 들어있는 것
  • 그 다음으로 중요한 개념을 뽑아보자면 prototype