Juni_Dev_log

(node.js) [Part.1] 노드로 만들 수 있는 대표적인 서버와 용도 - 비동기 입출력 방식, 이벤트 기반 입출력 방식, 모듈 본문

Theorem (정리)/node.js

(node.js) [Part.1] 노드로 만들 수 있는 대표적인 서버와 용도 - 비동기 입출력 방식, 이벤트 기반 입출력 방식, 모듈

Juni_K 2020. 11. 17. 11:52

노드란 무엇일까?

노드는 자바스크립트를 이용해서 서버를 만들 수 있는 개발 도구이다.

그런데, 이미 서버를 만드는 개발도구는 수없이 많은데 왜 하필 노드를 사용해야한느 것일까?

 

노드라는 개발도구가 새로 만들게 된 이유는 단순하다.

노드는 2009년에 라이언 딜이 만들었는데 당시에는 웹 서버에 파일을 올릴 때, 업로드가 완료되기 전까지 웹 서버에서 데이터를 조회하거나 하는 등의 다른 작업을 할 수 없었다.

이 문제를 해결하기 위해서 새로운 방식의 서버 개발 도구를 만들기 시작했는데 그것이 바로 노드이다.

 

웹 서버에 파일을 업로드하면서 다른 작업을 동시에 처리하기 힘든 문제가 있었다.

 

웹 브라우저를 통해 내 PC에 있는 문서 파일 하나를 업로드하고 싶다면

먼저, 웹 서버에 업로드를 요청해야한다.

이 때 웹 서버에 파일 업로드 기능을 담당하는 핸들러를 만들었다고 가정해보자.

그런데 파일의 크기가 크다면 파일을 업로드하는데 1분 또는 그 이상의 시간이 걸릴 수 있다.

그런데 파일 업로드를 완료하기 전에는 서버에 다른 파일의 정보를 확인하거나 어떻게 진행되고 있는지 요청하는 것이 불가능해서 업로드가 완료될 때까지 기다려야한다.

지금은 많은 방법으로 해결이 가능하지만, 그 당시에는 응답시간이 굉장히 길어지거나 서버에서 처리해야하는 요청의 수가 증가하면서 CPU나 메모리 사용량도 크게 증가하는 문제가 많이 발생했었다.

 

① 노드의 비동기 입출력 방식

이러한 문제를 해결하기 위해서 만든 것이 노드이다.

즉, 하나의 요청 처리가 끝날 때까지 기다리지 않고 다른 요청을 동시에 처리할 수 있는, "비동기 입출력(Non-Blocking IO)" 방식을 적용했다. 

 

비동기 입출력 방식은 노드의 대표적인 특징이다. 비동기 입출력 방식을 이해하려면  반대되는 의미인 "동기 입출력(Blocking IO)"방식으로 파일을 읽는 과정을 먼저 알아보자.

 

(동기 입출력 방식으로 파일을 읽어오는 경우)

  <프로그램>                         <파일 시스템>
1. 파일 기능 ----(읽기 요청)-----> 파일 준비
     (대기)
                                        2. 파일 준비 --------> 파일 처리

3. 데이터 처리 <---------------------------------------- 파일 처리

4. 데이터처리 -> 다른 작업 진행                  

처음에는 프로그램을 먼저 파일 시스템에 읽기 요청을 한다. 이 때 파일 시스템에서는 디스크에 있는 파일을 확인하고 준비한 다음 처리하는 시간이 필요한데, 그동안 프로그램은 다른 작업을 하지 않고 대기하게 된다.

프로그램이 아무 동작하지 않게 되는 것이다. 

프로그램이 파일의 내용을 읽어와 그 내용을 화면에 보여준 다음에야 다른 작업을 진행할 수 있다.

결국 프로그램을 실행하는 중간중간 대기 시간이 발생하면서 속도가 느려지는 문제가 발생하게 되는 것이다.

 

그런데 이를 비동기 입출력 방식으로 바꾸면 파일을 읽어 들일 때 대기하는 시간이 짧아진다.

 

(비동기 입출력 방식으로 파일을 읽어오는 경우)

  <프로그램>                         <파일 시스템>
1. 파일 기능 ----(읽기 요청)-----> 파일 준비
       ↓
  다른 작업 진행(대기 안 함)

                                          2. 파일 준비 --------> 파일 처리

3. 데이터 처리 <---------------------------------------- 파일 처리

4. 데이터처리 (콜백함수)

"파일을 비동기 방식으로 읽는다" 는 것은 파일 시스템에 읽기 요청을 한 후에 프로그램이 대기하지 않고, 다른 작업을 진행한다는 것을 의미한다.

그러면 어떻게 프로그램에서 다른 작업을 진행하는 중간에 파일 시스템에서 파일 처리를 할 수 있는 걸까?

또한, 프로그램에서 파일을 위한 작업은 언제 다시 시작할 수 있을까?

 

프로그램에서 해당 파일의 내용을 처리할 수 있는 시점이 되면 콜백함수가 호출된다. 프로그램에서 파일 읽기 요청을 하기 전에 콜백함수를 등록하는데, 파일 시스템은 파일 처리가 끝나면 자동으로 콜백함수를 호출한다.

따라서, 프로그램이 파일 읽기 작업이 끝날 때까지 대기하지 않아도 파일을 다 읽은 시점에서 통보를 받고 파일의 내용을 화면에 보여주는 작업을 진행할 수 있다.

 

더 쉽게 이해 할 수 있도록 동기와 비동기 방식으로 코드를 비교해보자.

더하기 함수를 실행하려고 할 때 만들어야하는 코드이다.

// 동기 입출력 방식
var contents = file.read('a.txt');
...
// 대기 //
doShow(contents);
var result = doAdd(10, 10);

동기 입출력 방식으로 작성한 코드는, file.read 코드를 실행해서 파일의 내용을 읽어온 후에, doShow() 함수를 실행해서 파일에서 읽어온 결과를 화면에 보여주고, 화면을 보여준 후에 doAdd() 함수로 다른 작업을 진행한다. 

그렇기에, doAdd() 함수는 이 프로그램의 제일 마지막에 실행된다.

// 비동기 입출력 방식
file.read('a.txt',function(contents){
	doShow(contents);
})
var result = doAdd(10, 10);

하지만, 비동기 입출력 방식으로 작성한 코드는 다르다.

똑같은 기능을 하지만, file.read() 함수를 실행할 때 파일 이름뿐만 아니라 파일을 다 읽었을 때 실행할 함수도 파라미터로 전달한다.

이 때문에 파일을 읽어 들이는 시간이 오래 걸리더라도 대기하지 않고 doAdd() 함수를 먼저 실행할 수 있다.

파일을 읽는 작업이 완료되었다면 file.read() 함수를 실행할 때 전달했던 함수가 자동으로 호출한다. 이러한 함수가 바로 콜백함수이다.

 

★ 콜백함수의 정의를 명확하게 알아두자

자바스크립트에서 변수를 할당할 수 있다. 따라서 변수에 할당된 함수를 다른 함수의 파라미터로 전달할 수 있다. 이렇게 파라미터로 전달된 함수를 다른 함수의 내부에서 호출하는 것이 콜백 함수이다.

이렇게 파일 읽기가 완료되었을 때 파일 시스템에서 콜백 함수를 호출하는데, 파일 시스템이 이벤트와 함께 호출하는 방식이면 이벤트 기반 입출력 모델 이라고 부른다.

 

논블로킹 방식

               ←     file.read('a.txt', ...
                                 ↓
a.txt                    var result = doAdd(10, 10);
          complete
               →      function(contents){doShow(contents)}
         이벤트 전달

파일 읽기가 완료되었다는 이벤트만 전달하면 프로그램에서는 그 이벤트를 받아 콜백함수를 실행할 수 있으며, 콜백함수는 이벤트가 발생하기 전에 미리 등록한다.

 

이로 인해, 노드에서 사용하는 이 모델은 상당히 가볍고 효율적이며 많은 데이터를 주고받는 실시간 프로그램에 큰 효과를 발휘할 수 있다.

② 노드에서 구현하는 이벤트 기반 입출력 방식

데이터 처리 방식을 비동기 방식으로 바꾸어도 자바스크립트 코드를 실행하는 속도가 느리면 효율성이 떨어질 수 있다.

자바스크립트는 코드를 한 줄씩 해석하면서 실행하는 인터프리터 방식을 사용하기 때문에, 속도가 느려 문제가 되곤 했다.

이러한 문제는 크롬의 V8 자바스크립트 엔진이 나오면서 해결됐다. V8 엔진은 자바스크립트 코드를 네이티브 코드로 바꾼 다음 실행할 수 있었는데 이 V8엔진을 통해서 자바스크립트 코드를 빠르게 실행할 수 있게 되었다.

 

다음 그림은 V8 엔진에서 노드가 동작할 수 있도록 만든 시스템 구조(아키택처)를 보여준다.

 

V8엔진에서 동작하는 노드의 아키택처

노드를 설치한 다음, 노드로 프로그램을 만들어 실행하면 크롬 V8엔진 위에서 실행된다.

V8엔진에는 필요한 기능을 병렬로 실행하는 "스레드 풀" 과 이벤트를 받아 처리하는 "이벤트 루프" 등의 기본 기능이 있다. 그 위에 소켓(Socket) , http 라이브러리 등이 있다.

 

그리고 다시 그 위에 표준 라이브러리가 구현되어 있다. 이 라이브러리를 사용하고 싶다면 자바스크립트로 프로그램을 만들면 된다. 개발자들이 각자의 목적에 맞게 만든 노드 프로그램은 그 라이브러리 위에서 동작하게 된다.

 

노드 프로그램이 동작할 수 있도록 만든 이 아키택처에서 가장 중요한 부분 중 하나가 바로 이벤트를 받아 처리하는 기능이다.

특히 노드는 서버 쪽에서 동작하는 프로그램을 만드는 것이 주 임무이기 때문에, 기본 기능인 소켓이나 HTTP 프로토콜을 사용해 데이터를 송수신하는 기능을 포함하고 있다.

따라서, 데이터 송수신 부분에서도 이벤트 처리 방식을 그대로 사용할 수 있다.

 

http 를 이용해 웹 서버로 요청을 보내고 응답을 받는 방식

 

http 객체는 HTTP 프로토콜로 웹 서버에 데이터를 요청할 수 있는 기능이 있다.

request() 함수를 호출하여 웹 서버에 데이터를 요청할 수 있고, 응답을 받으면 콜백함수가 자동으로 호출된다.

응답을 처리할 수 있는 콜백함수는 res라는 이름의 객체로 전달받는데, 이 res 객체는 수신한 데이터를 이벤트이름으로 구별할 수 있다.

예를 들어, data 이벤트가 있을 때 이 이벤트 이름으로 콜백 함수를 등록하면 등록한 콜백함수에 data이벤트로 전달된 응답 데이터가 전달된다.

 

자바스크립트에서는 on() 메소드를 사용해서 이벤트를 콜백 함수와 바인딩할 수 있다.

따라서 응답 객체인 res객체의 on()메소드를 사용해 data 이벤트와 콜백 함수를 바인딩하면, data라는 이름의 이벤트를 받았을 때, 등록한 콜백함수가 실행된다.

앞에서 본 코드에서는 이벤트 이름이 data이며, 응답으로 받은 데이터는 chunk 변수에 들어 있다.

 

이벤트를 바인딩한다는 것이 어떤 의미일까?

바인딩(Binding)이란 서로 묶어서 연결해준다는 의미이다. 

예를 들어, 버튼이 하나 있는데 이 버튼을 눌렀을 때 click 이벤트가 발생한다고 가정해보자.
이 때 click 이벤트를 함수 객체와 바인딩하면 이 click 이벤트가 발생했을 때, 등록한 함수 객체가 실행된다.

즉, 사용자가 버튼을 클릭하면 함수가 실행되는 것이다.

[객체].one([이벤트 이름], [함수 객체]);

res.on('data', function() {...});

 

③ 노드를 더 쉽게 사용할 수 있게 하는 모듈

소스 파일 하나에 실행하려는 기능이 모두 들어있다면 코드의 양이 많아질 뿐만 아니라 복잡해진다.

웹 브라우저에서 사용하는 자바스크립트는 확장자가 js인 별도의 파일로 만들면 코드를 분리해서 관리할 수 있고 필요할 때 불러서 관리하고 사용할 수 있다.

이와 마찬가지로, 노드에서도 필요한 기능을 별도의 자바스크립트로 만든 후. 필요할 때마다 불러올 수 있다.

 

노드에서 코드를 각각의 파일로 분리시킨 후, 필요할 때 불러와 사용하는 과정을 살펴보자.

 

노드의 모듈 사용 방식

먼저 메인이 되는 자바스크립트 파일의 일부 코드를 떼어 별도의 파일로 만들 수 있는데, 이를 모듈(Module) 이라고 부른다.

 

예를 들어, 코드의 일부를 떼어 module_1.js 라는 이름의 파일로 저장한다면 이 파일이 모듈이다.

그리고 이 파일에 들어 있는 고크들 사용하고 싶다면 require() 함수로 모듈을 호출하면 된다.

이렇게 불러들인 파일은 자바스크립트 객체로 인식되며, 그 객체를 참조하여 파일에 넣어 둔 기능을 사용할 수 있다.

 

이렇게 여러 프로그램에서 공통으로 사용하는 기능은 모듈로 분리하여 구성하는 것이 일반적이다.

또 여러 개의 모듈을 합쳐서 하나의 패키지(Package)로 두면, 다른 프로그래머들도 npm 프로그램으로 손쉽게 패키지를 설치하여 사용할 수 있다.

 

노드에서 모듈을 어떻게 만들고 어떻게 사용하는지 그리고 npm을 어떻게 사용하는지는 나중에 코드를 만들면서 이야기해보자.

 


 

지금까지 노드의 주요 특징을 알아보았다.

 

노드의 주요 특징

자바스크립트는 수많은 웹 개발자들이 이미 사용하는 프로그래밍 언어이다. 따라서, 자바스크립트에 익숙한 전 세계의 많은 개발자들이 노드를  쉽게 이해하고 사용할 수 있다.

특히, 웹 브라우저에서 주로 사용하던 자바스크립트 언어가 서버에도 적용되어, 자바스크립트만 알면 웹 브라우저에서 동작하는 클라이언트 기능서버에서 동작하는 프로그램모두 만들 수 있다.

또한 몽고디비 데이터베이스를 사용하면 자바스크립트에서 사용하는 객체를 그대로 저장할 수 있기 때문에, 데이터베이스를 다루는 것도 굉장히 쉬워진다.

 

이 외 노드는 여러 가지 장점이 많다. 

이미 만들어 놓은 모듈들이 굉장히 많기 때문에, 개발자가 새로운 기능을 만들 필요가 없을 뿐만 아니라 마이크로소프트, 페이팔, 야후 같은 글로벌 대기업들이 노드를 사용하면서 안정성도 충분히 검증되었다.

최근에는 사용할 수 있는 모듈의 수가 폭발적으로 증가하고 있으며, 클라우드의 성장과 더불어 빠르게 발전해 이제 노드는 서버를 구축할 때 필수로 배워야할 개발 도구이자 플랫폼이 되었다.

Comments