과목명 : 웹 서버 프로그래밍(Web Server-side programming with Node.js)
수업일자 : 2023년 03월 09일 (목)
1. Node.js(노드)의 정의
1-1. Node.js 정의 (공식 홈페이지)
- Node.js는 Chrome V8 자바스크립트 엔진으로 빌드된 자바스크립트 런타임으로, Node.js는 이벤트 기반, Non-Blocking I/O 모델을 사용해 가볍고 효율적이며 Node.js의 패키지 생태계인 npm은 세계에서 가장 큰 오픈 소스 라이브러리 생태계이기도 합니다.
1-2. 런타임(Runtime)
- 컴퓨터 과학에서 런타임은, 컴퓨터 프로그램이 실행되고 있는 동작을 의미합니다.
1-3. 이벤트 기반(Event-driven)
- 특정 이벤트 발생에 의해 프로그램의 실행 흐름이 결정되는 프로그래밍 패러다임
1-4. Non-Blocking I/O
- 간단히 설명하면, I/O 작업이 진행되는 동안 프로세스의 작업을 중단시키지 않는 방식을 의미합니다.
2. 런타임(Runtime)
2-1. Node.js에서의 런타임이란?
- 자바스크립트의 런타임(Runtime, 실행 환경)을 의미하며 자바스크립트 언어로 작성된 프로그램들을 실행할 수 있게 해 주는 일종의 가상 머신(Chrome의 V8 자바스크립트 엔진)의 상태입니다.
- 자바스크립트를 실행할 수 있는 또 다른 런타임 환경은 웹 브라우저가 존재합니다.
- Node.js 이전에도 브라우저 이외의 환경에서도 자바스크립트 런타임 환경을 구현하기 위한 많은 시도가 있었지만 자바스크립트의 엔진 속도 문제로 모두 실패했습니다.
3. Node.js의 내부 구조
- 2008년에 구글에서 V8 엔진이 출시하였으며, V8 엔진의 빠른 속도를 발판 삼아 2009년 Node.js 프로젝트가 시작되었습니다.
(1) 위의 구조처럼 Node.js는 libuv라는 라이브러리를 사용합니다.
- libuv 라이브러리는 Node.js의 특성인 이벤트 기반(Event-driven), Non-blocking 모델을 구현하고 있습니다. 위와 같은 특성으로 가볍고 효율적인 성능을 낼 수 있게 되었습니다.
(2) Chrome V8 엔진을 사용함으로써 이전 자바스크립트 엔진의 속도 문제가 개선되었습니다.
4. 이벤트 기반(Event-driven)
4-1. 이벤트 기반(Event-driven)의 정의
- 이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식을 의미합니다.
- 노드는 이벤트가 발생하면, 이벤트 리스너에 등록된 콜백 함수를 호출합니다. 발생한 이벤트가 존재하지 않거나 이벤트를 모두 처리했다면 노드는 다음 이벤트가 발생할 때까지 대기하게 됩니다.
(1) 이벤트의 예시
- 브라우저에서의 특정 버튼이나 메뉴 클릭, 네트워크 요청, 타이머 등
(2) 이벤트 리스너(Event Listener)
- 이벤트를 등록하는 함수
(3) 콜백 함수(Callback function)
- 이벤트가 발생했을 때 실행되는 함수
4-2. 이벤트 기반 방식을 예제를 통해 확인해 보기 (1)
- 우선 위의 코드는 function 키워드로 first(), second(), third() 함수를 선언하였으며 이후에 first() 함수를 호출한 후의 결과를 나타낸 코드입니다.
- main() 함수가 먼저 실행되고 main() 함수에서 first() 함수를 호출한 뒤, first() 함수 내부의 second() 함수가 호출된 뒤 second() 함수 내부의 third() 함수가 실행됩니다.
- Call Stack은 전형적인 LIFO(Last In First Out) 구조를 가짐으로써 이를 통해 호출된 순서와는 반대로 실행이 완료되는 것을 알 수 있으며 각 함수의 실행이 완료되면 호출 스택에서 함수가 삭제됩니다. third(), second(), first(), main() 함수 순으로 지워지고 main() 함수까지 실행 완료되었다면 main() 함수도 호출 스택에서 지워지게 됩니다.
4-3. 이벤트 기반 방식을 예제를 통해 확인해 보기 (2)
- Java, C++와 같은 프로그래밍 언어를 학습하신 분들이 이 코드를 본다면 위와 같은 수행 결과를 납득하기 어려우실 수도 있습니다. 순차적으로 실행되어야 한다면 "start → 3초 후 실행 → finish"가 확인되어야 하나 전혀 다른 결과가 발생했기 때문입니다.
- 위와 같은 실행 결과는 앞서 설명했던 노드의 특성 중 하나인 Non-blocking I/O 방식으로 이벤트 루프가 동작하기 때문이며 아래에서 더 자세히 설명해 보도록 하겠습니다.
- 이 부분을 파악하기 위해 이벤트 루프, 태스크 큐, 백그라운드를 이해할 필요가 있습니다.
4-4. 이벤트 루프(Event loop)
- 이벤트 발생 시 호출할 콜백 함수를 관리하며 콜백 함수의 실행 순서를 결정합니다.
4-5. 태스크 큐(Task queue 또는 Callback queue)
- 이벤트 발생 후 호출되어야 할 콜백 함수들을 기다리는 공간입니다.
4-6. 백그라운드(Background)
- 타이머, I/O, 작업 콜백, 이벤트 리스너들이 대기하는 공간입니다.
(1) main() → setTimeout() 순서대로 호출 스택에 쌓입니다.
(2) setTimeout()이 실행되면 run() 콜백 함수를 백그라운드로 보내고, 호출 스택에서 빠지게 되며 이후 main() 함수도 호출 스택에서 빠지게 됩니다.
(3) 백그라운드에서는 코드 값에 맞게 3초를 센 후 run() 콜백 함수를 태스크 큐로 이동시킵니다.
(4) 호출 스택이 모두 비워지게 된 상황입니다.
(5) 호출 스택에 함수가 존재하지 않으므로 이벤트 루프는 이때 태스크 큐에 존재하는 콜백 함수를 호출 스택으로 이동시킵니다.
(6) 호출 스택으로 이동된 run() 함수가 실행되고 실행이 완료되면 호출 스택에서 사라지게 됩니다.
(7) 이후에 이벤트 루프는 태스크 큐에 콜백 함수가 들어올 때까지 대기 상태로 존재합니다.
5. Non-Blocking I/O (Input / Output)
5-1. Non-Blocking I/O 정의
- 컴퓨터 과학에서는 비동기 입출력이라고도 정의되며 다른 주체의 작업 처리 여부와 관계없이 자신의 작업을 수행하는 방식입니다.
- Node.js에서는 수행이 오래 걸리는 함수를 백그라운드로 보내고, 이후 코드가 먼저 실행되게 한 후 그 함수가 다시 태스크 큐를 거쳐 호출 스택으로 올라와 처리되는 방식을 의미합니다.
(1) Non-Blocking 방식 하에서 일부 코드들은 백그라운드에서 병렬로 실행되기도 합니다.
- 여기서 말하는 일부 코드는 특정 I/O 작업(파일 시스템 접근, 네트워크 요청 등), 압축, 암호화 등을 의미
(2) 나머지 코드는 Blocking 방식으로 실행됩니다.
(3) 이처럼, Node.js를 사용하면 I/O 작업이 많은 환경에서 효율을 끌어올릴 수 있습니다.
(4) 위의 그래프를 보면 동일한 작업을 수행하더라도 Non-Blocking 방식이 더 빠르게 처리됨을 알 수 있습니다. 단 노드가 가지는 싱글 스레드라는 한계 때문에 모두 시간적 이득을 볼 수 있는 것은 아니며 노드 프로세스 외의 시스템 자체 내의 자원을 모두 활용할 때 I/O 작업을 수행함으로써 좀 더 효율을 낼 수 있는 부분인 점을 인지해야 합니다.
6. Non-Blocking I/O 방식의 예제 코드 확인해 보기
6-1. 예제 1
- 이벤트 루프 코드처럼 Chrome의 개발자 모드 콘솔 환경에서 확인해 보겠습니다.
- 결과를 예상한 것처럼 "시작 → 작업 종료 → 다음 작업" 이 로그에서 확인되었습니다.
6-2 예제 2 (Non-Blocking 방식 강제 구현하기, setTimeout(callbackFunciton, 0) 사용)
- 강제로 Non-Blocking 방식을 구현하기 위해 setTimeout(callbackFunciton, 0) 함수를 사용하였습니다.
- 해당 함수를 사용하면 이벤트 루프 처리에 의해 setTimeout()의 콜백 함수 longRunningTask2()가 태스크 큐로 이동되므로 순차적으로 실행되지 않는다는 것을 이해할 수 있습니다.
- 현재 setTimeout() 함수의 두 번째 전달인자의 값이 0임에 따라 0ms가 되므로 바로 순차적으로 실행되어야 하는 것으로 생각할 수 있지만 HTML5 브라우저에서는 4ms, Node.js 환경에서는 1ms의 지연시간이 존재하기 때문에 위와 같은 실행 결과가 얻어지게 됩니다.
7. 프로세스와 스레드(Process & Thread)
7-1. 프로세스와 스레드의 차이
(1) 프로세스(Process)
- 운영체제에서 할당해 주는 작업의 단위이며 프로세스 간의 자원 공유는 발생하지 않습니다.
(2) 스레드(Thread)
- 프로세스 내부에서 실행되는 작업의 단위이며 하나의 프로세스는 여러 개의 스레드를 가질 수 있습니다. 이러한 스레드들은 부모 프로세스의 자원을 공유할 수 있습니다. (같은 메모리에 접근 가능)
7-2. 자바스크립트와 노드에서의 Single thread 방식
- 자바스크립트와 노드에서 Non-Blocking 방식이 중요한 이유는 바로 싱글 스레드 방식으로 작업을 처리하기 때문입니다.
- 엄밀히 말하면 노드는 싱글 스레드가 아닙니다. 노드도 여러 개의 스레드를 보유하고 있으나 자바스크립트를 실행하는 스레드는 단 하나이므로 노드를 싱글 스레드 방식이라고 부르고 있는 것입니다. 해당 싱글 스레드가 바로 위에서 언급된 이벤트 루프입니다.
- Node 10 버전부터 멀티 스레드 방식을 지원하긴 하지만 불안정(Unstable)한 부분이 크기 때문에 여전히 싱글 스레드 방식으로 작업을 처리합니다.
8. 싱글 스레드(Single thread - Blocking, Non-Blocking 방식), 멀티 스레드(Multi-thread) 모델과 비교
8-1. 싱글 스레드, Blocking 방식
- 하나의 프로세스에 대해 단일 스레드를 통해 작업을 처리하는 방식입니다.
- 여기서 Blocking이 발생하는 경우 수행되던 나머지 작업들은 모두 대기 상태로 변경됩니다.
- 식당에서의 점원과 고객으로 비유한다면, 점원이 한 손님의 오더를 받아 주방에 넘기고 주방에서 요리가 나온다면 해당 고객에게 서빙을 합니다. 이후에 다음 손님의 주문을 받는 방식으로 매우 비효율적입니다.
8-2. 싱글 스레드, Non-Blocking 방식
- 싱글 스레드에서 Blocking 방식 대신, Non-Blocking 방식을 채택한 방법입니다.
(프로그래밍이 간결하고 시스템 자원을 적게 사용)
- 우선 요청을 받고 이후에 처리가 완료됐을 때 응답할 수 있는 방식입니다.
- 현재 노드가 채택하고 있는 방식이며 해당 방식은 스레드가 중간에 멈추지 않도록 관리가 필요하며 만약 오류 등으로 인해 스레드가 멈춘다면 서버가 아예 멈추게 됩니다.
- 마찬가지로 주방과 점원, 고객으로 비유해본다면 점원이 한 손님의 주문을 받고 주방에 주문 내역을 넘긴 뒤 다음 손님의 주문을 받게 되며 주방에서 요리가 완료되면 순서대로 손님에게 서빙합니다. 이 과정에서 주문 순서와 서빙 순서가 일치하지 않을 수도 있습니다.
8-3. 멀티 스레드, Blocking 방식
- 각 요청마다 추가적인 스레드가 할당되어 작업을 처리하는 방식.
(프로그래밍이 다소 어렵고, 시스템 자원을 많이 사용하게 됨)
- 비유로 상황을 설명해 보면 고객마다 점원이 붙어서 전적으로 처리하는 방식입니다.
- 멀티 스레드 방식은 에러가 발생해도 새로운 스레드를 생성하여 처리할 수 있는 장점이 있어서 싱글 스레드 방식보다 좋은 것 같지만, 큰 단점이 존재합니다. 만약 고객의 수가 늘어날수록 그만큼 점원의 수도 늘려야 하고 손님의 수가 줄어들게 되면 이 과정에서 일을 하지 않는 점원도 발생할 수 있습니다. 이를 통해 점원을 고용하는 과정, 놀기만 하는 직원을 해고하는 과정에서 큰 비용 소모가 발생하게 됩니다.
9. 서버로서의 Node.js(노드)와 서버 외의 Node.js(노드)
9-1. 서버와 클라이언트
(1) 서버(Server)
- 클라이언트의 요청에 따라 각 요청에 맞는 적절한 응답을 클라이언트에게 전달해 주는 시스템 또는 소프트웨어를 의미합니다.
(2) 클라이언트(Client)
- 서버에게 요청을 보내는 주체입니다.
- 여기서 주체는 브라우저, 데스크탑 프로그램, 모바일 앱, 다른 서버에서 요청을 보내는 서버 중 하나가 될 수 있습니다.
9-2. 서버로서의 Node.js(노드)
(1) 위에서 언급된 것처럼 노드는 싱글 스레드, Non-Blocking 모델을 사용하므로 노드를 사용하는 서버 또한 동일한 모델일 수밖에 없습니다.
(2) 노드로 구현된 서버는 I/O가 많은 작업에 적합하지만 이미지 또는 비디오 처리나 대규모 데이터 처리와 같이 CPU의 고도의 연산이 요구되는 작업에서는 노드를 사용하는 것이 적합하지는 않습니다.
(3) 싱글 스레드는 프로그래밍 난이도가 쉬운 편이라 서버 사이드 프로그래밍에 익숙하지 않은 개발자도 쉽게 입문 가능하다는 장점이 있으나 싱글 스레드가 멈추지 않도록 잘 관리해 줘야 하며 싱글 스레드가 에러 등으로 멈추는 순간 서비스도 같이 멈추게 되므로 발생할 수 있는 에러에 대한 예외 처리도 중요합니다.
(4) 이처럼 노드를 사용하면 노드가 서버를 구성할 수 있도록 하는 모듈을 자체적으로 제공하기 때문에 노드를 통해 서버를 구성할 수 있는 것이며, "노드 = 서버"는 아닌 점을 알고 있어야 합니다.
Node.js(노드)의 장점 | Node.js(노드)의 단점 |
멀티 스레드 방식과 비교했을 때 시스템 자원을 적게 사용한다. |
싱글 스레드 방식으로, CPU의 코어를 한 개만 사용한다. |
I/O 작업이 많은 서버로 적합하다. | CPU 연산 등 작업이 많은 서버로서는 부적합하다. |
멀티 스레드 방식보다 구현하기 쉬움. | 하나의 스레드가 멈추지 않도록 관리가 필요하다. |
웹 서버가 내장되어 있다. | 서버 규모가 커질 경우 서버를 관리하기 어려워진다. |
자바스크립트를 사용한다. | 성능이 뛰어나진 않다.(어중간한 성능) |
JSON 형식과 호환하기 쉽다. |
- 최근에는 고도화된 CPU 연산 작업을 위해 AWS Lambda, Google Cloud Functions과 같은 별도의 서비스에서 노드로 CPU 작업을 처리할 수 있도록 지원해 주고 있습니다.
9-3. 서버 외의 Node.js(노드)
- 노드는 자바스크립트 런타임이므로, 서버에서만 노드를 사용하는 것이 아니라 현재는 사용 범위가 점점 확대되어 웹, 모바일, 데스크탑 애플리케이션 개발에 사용되고 있습니다.
9-4. 노드를 기반으로 하는 다양한 프레임워크
(1) 프론트엔드 엔지니어링 : React.js, Angular.js, Vue.js, Meteor(또는 MeteorJS) 등
(2) 모바일 앱 프레임워크 : React Native, Ionic Framework, NativeScript
(3) 데스크탑 애플리케이션 개발 도구 : Electron 기반으로 제작된 애플리케이션 (Atom, Slack, VSCode, Discord 등)
10. 개발 환경 설정
10-1. Node.js installation
공식 URL : https://nodejs.org/en/
(1) LTS version
- 기업을 위해 3년간 지원하는 버전으로, 짝수 버전에만 LTS 버전이 적용되었습니다.
- 안정적인 서버 운영을 고려할 때 사용할 수 있으나 추가된 최신 기능을 사용하지 못할 수도 있습니다.
(2) Current version
- 최신 기능을 보유하고 있는 버전이지만 다소 실험적인 기능을 보유해 예상하지 못한 에러가 발생할 수 있는 버전입니다.
- 학습용으로 많이 사용됩니다.
10-2. VSCode installation
공식 URL : https://code.visualstudio.com/
10-3. 개발 환경 설정 후 Node, npm version 조회하기
- 정상적으로 설치되었다면 Node, npm version이 커맨드라인에 출력되어야 합니다.
11. Reference
Node.js 교과서(Node.js Textbook) - 저자 : 조현영
https://www.zerocho.com/book/1
- 학부에서 수강했던 전공 수업 내용을 정리하는 포스팅입니다.
- 내용 중에서 오타 또는 잘못된 내용이 있을 시 지적해 주시기 바랍니다.
'전공 수업 > 웹 서버 프로그래밍(Node.js)' 카테고리의 다른 글
[5주 차] - Node.js를 위한 JavaScript 기본 문법 (3), REPL, Node의 Module, 내장 객체(global, console) (0) | 2023.04.01 |
---|---|
[4주 차] - 변수 키워드 const, let, var 주요 정리, Node.js를 위한 JavaScript 기본 문법 (2) (0) | 2023.03.29 |
[3주 차] - Node.js를 위한 JavaScript 기본 문법 (0) | 2023.03.17 |
[Node.js] - VSCode에서 yarn command가 실행되지 않는 경우 (0) | 2023.03.14 |
[1주 차] - 웹 서버 프로그래밍 수업 개요 (0) | 2023.03.02 |
댓글