Study/Node.js

노드란 무엇일까?

AC 2019. 3. 6. 03:16



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


노드라고도 부르고 노드제이에스라고도 부른다.


서버를 만드는 개발 도구는 굉장히 만은데 왜 하필 노드를 사용하는지에 대해서부터 알아보자.



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


2009년에 라이언 달리(Ryan Dahl)로부터 만들어진 노드는 

그 당시 웹 서버에 파일을 업로드할 때,업로드가 완료되기 전까지 

웹 서버에서 데이터를 조회한다거나 하는 등의 다른 작업을 할 수 없었다고 한다.


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





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





웹 브라우저를 통해 내 PC에 있는 문서 파일 하나를 업로드하고 싶다면 먼저 웹 서버에 업로드를 요청해야 한다.

이 때 웹 서버에는 파일 업로드 기능을 담당하는 핸들러(Handler)를 하나 만들어 둔다.


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


그런데 파일 업로드를 완료하기 전에는 서버에 있는 다른 파일의 정보를 확인하거나 

파일 업로드가 어떻게 진행되고 있는지 요청하는 것이 불가능해서 업로드가 완료될 때까지 대기해야 한다. 


지금은 이런 문제를 해결할 수 있는 여러가지 방법이 나와 있어 큰 문제가 되지 않는다. 


하지만, 그 당시에는 웹 서버의 파일 업로드 핸들러가 하나의 요청이 끝날 때까지 다른 요청을 대기시켜 응답 시간이 길어지거나, 


서버에서 처리해야 하는 요청의 수가 증가하면 CPU나 메모리 사용량도 크게 증가하는 문제가 많이 발생했다.




노드의 비동기 입출력 방식


이런 문제를 해결하기 위해 만든 것이 노드이다. 즉, 하나의 요청 처리가 끝날 때까지 기다리지 않고 다른 요청을 동시에 처리할 수 있는 비동기 입출력(논블로킹 입출력, Non-Blocking IO) 방식을 적용했다.


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



▲ '동기 입출력' 방식으로 파일을 읽는 경우



PC에 있는 파일의 내용을 읽어오는 동기 입출력 방식의 프로그램을 만들었다면 그 프로그램은 먼저 파일 시스템에 읽기 요청을 한다.

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



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


결국 실행하는 중간중간 대기 시간이 발생하면서 속도가 느려지는 문제가 발생한다.



그런데 이것을 비동기 방식으로 변경하면 파일을 읽을 때까지 대기하는 시간이 없어지는 이점이 생긴다.



▲ '비동기 입출력' 방식으로 파일을 읽는 경우


파일을 '비동기 방식으로 읽는다'는 것은 파일 시스템에 읽기 요청을 한 후에 프로그램이 대기하지 않고 다른 작업을 진행한다는 것을 의미한다. 그러면 어떻게 프로그램에서 다른 작업을 진행하는 중간에 파일 시스템에서 파일 처리를 할 수 있을까?



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


프로그램에서 해당 파일의 내용을 처리할 수 있는 시점이 되면 콜백 함수(Callback Function)가 호출된다.


프로그램에서는 파일 읽기 요청을 하기 전에 콜백 함수를 등록하는데, 파일 시스템은 파일 처리가 끝나면 자동으로 콜백 함수를 호출한다.


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



▲ 동기(Blocking IO) 방식과 비동기(Non-Blocking IO) 방식의 코드 패턴 비교




어떤 차이를 갖는지 이해가 되는가?


먼저 왼쪽의 동김(블로킹)방식으로 표현한 코드를 보자.


file 객체가 파일을 나타내고 그 객체에 정의된 함수 중에서 파일을 읽어 들이는 함수를 read()라고 하면, file.read()코드를 실행해서 파일의 내용을 읽어올 수 있다. 이 때 파일의 내용을 다 읽어 올 때까지 프로그램은 대기하고, 읽는 작업이 끝나야 doShow()함수를 실행하여 파일에서 읽어온 결과를 화면에 뿌려준다.




파일의 내용을 다 보여준 후에 doAdd()함수를 실행하여 다른 작업을 실행할 수 있는 것이다.

이 doAdd()함수는 두 개의 숫자를 더하는 더하기 함수를 미리 만들어 둔 것이며, 이 프로그램의 가장 마지막에 실행된다.



하지만, 똑같은 기능을 실행하는 오른쪽의 비동기 방식으로 표현한 코드는 file.read() 함수를 실행할 때 파일의 이름뿐만 아니라 파일을 다 읽었을 때 실행할 함수도 파라미터로 전달한다. 


파일 읽기를 요청한 다음에는 파일을 다 읽어 화면에 보여주기 전이라도 doAdd()함수를 호출한다. 이 때문에 파일을 읽어 들이는 작업 시간이 오래 걸리더라도 대기하지 않고 doAdd()함수를 먼저 실행할 수 있다.


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


이 함수가 바로 콜백 함수(Callback Function)이다.




▲ 동기(블로킹) 입출력 방식과 비동기(논블로킹) 입출력 방식의 코드 실행 순서 비교



왼쪽의 경우에는 첫 번째 코드 줄이 실행된 후 대기하는 시간이 있고, 파일 시스템에서 파일 읽기가 완료되었따고 알려 주면 대기 시간이 끝난다.


대기 시간이 길어지더라도 doAdd() 함수는 실행되지 않고 계속해서 기다리게 될 것이다.


오른쪽의 경우에는 파일 읽기를 요청한 후 바로 이어서 doAdd() 함수를 호출한다. 파일 읽기가 끝나는 시점에 doShow() 함수가 자동으로 호출 된다. 파일 읽기가 완료되었을 때 파일 시스템에서 콜백 함수를 호출하는데, 파일 시스템이 이벤트와 함께 호출하는 방식이면


이벤트 기반입출력(Event Driven I/O) 모델이라고 부른다.




▲비동기(논블로킹) 입출력 방식에서의 이벤트 전달



파일 시스템에서 파일 읽기가 완료되었다는 이벤트만 전달하면 프로그램에서는 그 이벤트를 받아 콜백함수를 실행할 수 있으며,

콜백 함수는 이벤트가 발생하기 전에 미리 등록한다.


지금까지 살펴본 내용을 종합해 보면, 노드는 비동기 방식을 사용하는 이벤트 기반 입출력 모델(Event driven, Non-blocking I/O model)이다. 노드에서 사용하는 이 모델은 상당히 가볍고 효율적이며 많은 데이터를 주고받는 실시간 프로그램에서 큰 효과를 발휘 할 수 있다. 












LIST