Node.js

내위키

자바스크립트를 기반으로 하는 웹 서버. 2009년 란 달이라는 개발자가 구글 크롬자바스크립트 엔진인 V8에다 조이엔트란 곳에서 만든 비동기 I/O 라이브러리인 libuv를 붙이고 웹 서버에 필요한 모듈을 개발해서 만들었다. 싱글스레드에 비동기 방식을 기반으로 하고 있다.

이전까지 자바스크립트는 프론트엔드, 즉 웹 브라우저 쪽에서 구동되는 프로그래밍 언어로 주로 웹 페이지에 동적인 효과를 주기 위해서 많이 쓰였다. Ajax 덕분에 활용 폭이 넓어졌지만 그래도 프론트엔드로 한정되어 있다는 게 널리 퍼진 인식이었는데, Node.js가 인기를 얻으면서 백엔드, 즉 웹 서버 프로그래밍에도 자바스크립트가 폭발적으로 늘어나는 계기가 되었다. 자바스크립트 기반으로 웹 서버를 만들려는 시도는 그 전에도 있었지만 제대로 인기를 얻은 것은 Node.js다. 이를 통해서 자바스크립트 프로그래머들도 웹 서버 프로그래밍을 할 수 있게 되었고, 특히 개발자가 혼자 또는 소수인 스타트업은 프론트엔드와 백엔드 프로그래머를 따로 두지 않아도 되는 엄청난 이점을 얻게 되었다.

장점

Node.js가 가진 가장 큰 장점을 꼽으라면 빠른 처리 속도다. 아파치JBoss와 같은 서버들은 멀티스레드 혹은 멀티프로세스 기반이다. 즉, 연결 요청마다 프로세스나 스레드를 하나씩 배정한다. 반면 Node.js는 스레드가 딱 하나 뿐이고, 이 한 개의 스레드에서 모든 요청을 처리한다. 단, 모든 요청은 비동기 방식으로 처리된다.[1]

조금 더 쉽게 이야기해 보자면, 기존의 방식은 사용자 A가 서버에 접속해서 데이터베이스에 있는 데이터를 요청했을 때, 서버가 데이터베이스에 자료를 요청하고 응답이 올 때까지 기다린다. 메모리의 데이터를 읽고 쓸 때에 비해 디스크나 데이터베이스의 데이터를 읽고 쓸 때 걸리는 시간이 훨씬 길기 때문에 이 과정에서 CPU가 응답을 기다리면서 하염 없이 놀아버린다. 웹 서버는 많은 사용자가 접속해서 요청과 응답을 주고받으므로 CPU가 하염 없이 놀지는 않지만 사용자가 많으면 데이터베이스에 접근하는 사용자도 많으며, 데이터베이스가 동시에 처리할 수 있는 사용자 양을 넘어가면 앞 사용자가 데이터베이스 작업을 종료할 때까지 기다려야 하므로 결과적으로 웹 서버에서 CPU의 효율성은 떨어진다. 파일 업로드나 다운로드[2]와 같이 디스크 입출력에 부하를 주는 처리는 데이터베이스보다 훨씬 더 시간을 잡아먹는다.

반면 비동기 방식은 서버가 데이터베이스에 자료를 요청하면 응답을 기다리지 않고 다음 명령으로 넘어간다. 자료를 요청할 때, '자료가 들어오면 이 함수를 실행시키라'고 콜백함수를 넘겨주므로, 데이터베이스에서 응답이 오면 콜백함수가 실행된다. 쉽게 말해서, 답이 올 때까지 기다렸다가 받아가는 게 아니라 답이 나오면 연락을 달라고 연락처만 주고 가버리는 셈이다. 이런 식으로 싱글스레드에서 여러 연결을 빠르게 처리한다. 입출력 과정(I/O) 때문에 시스템이 놀고 있을 필요가 없으므로 이를 논블로킹 I/O(non-blocking I/O)라고 한다. 마치 예전에 반쪽짜리 멀티태스킹이었던 윈도우 3의 프로그램과 비슷한 방식이다. 이게 왜 빠르지? 할 수 있겠지만 프로세스나 스레드가 하나 생길 때마다 그만큼의 시스템 자원 소모가 발생한다. 하나의 프로세스가 생길 때마다 기본적으로 배분되는 메모리가 있기 때문에 만들 수 있는 프로세스의 수에는 한계가 있다. 또한 프로세스가 스레드를 관리하고 자원을 배분이라기 보다는 줬다 뺐었다하는 것 역시도 시스템 자원이 들어간다. 싱글스레드 기반에서는 이러한 자원 소모가 최소화되므로 상대적으로 시스템의 자원을 최대한 웹 서버 쪽으로 돌릴 수 있으므로 웹 서버 하나가 받아들일 수 있는 연결 요청이 더 많다.

앞서 말했지만 한 가지 프로그래밍 언어로 프론트엔드백엔드를 모두 다룰 수 있으므로 자바스크립트 개발자들의 활동 폭이 왕창 넓어지고, 통합적으로 개발할 수 있게 된 것도 장점 중에 하나. 둘을 잘 결합하면 웹 서버가 페이지를 보내는 부담을 줄이는 대신 웹 브라우저 쪽에서 그때 그때 Ajax로 데이터를 당겨가서 페이지를 업데이트하는 방식으로 단일 페이지 애플리케이션(Single-Page Application, SPA)을 구축하기에 편리하다.[3]

문제점

반면 가장 큰 문제는 에러가 생겼을 때 웹 서버가 통째로 죽어버리기 쉽다는 것이다. 멀티프로세스 혹은 멀티스레드라면 하나가 오류가 터져도 그 프로세스나 스레드만 정리하면 되지만 Node.js는 싱글스레드이므로 연결 중 하나에서 오류가 터지면 웹 서버가 싹 죽어버리는 것. 물론 웹 서버가 죽었을 때 자동으로 다시 실행시켜주는 모듈이 있지만 어쨌든 어느 한 연결의 오류로 연결된 전체 사용자가 일시적으로 서비스를 못 받는 문제가 터지기 쉽다.

또한 프로그래밍이 까다롭다. 멀티프로세스인 경우에는 각각의 프로세스는 자기 혼자 돌아가는 것처럼 생각하고 프로그래밍 되어도 웹 서버가 알아서 관리해 주지만 Node.js는 신경써야 할 게 많다. 멀티프로세스 하듯이 했다가는 한 연결이 CPU를 차지하고 앉아서 다른 연결이 먹통이 되는 일이 생기기 쉽다.[4] 특히 비동기화 처리를 위한 콜백 함수가 난무하다 보니, 함수의 매개변수로 함수를 넘기고, 또 그 함수의 매개변수로 함수를 넘기고, 하는 게 줄줄이 이어지다 보면 뭐가 뭔지 대가리가 터지기 시작한다. 코드도 알아보기도 힘들고 디버그도 오리무중이 되기 쉽다. 이러한 문제를 해결하기 위해서는 콜백함수를 함수 매개변수 부분에서 익명으로 정의하지 않고 별개로 정의하는 방법, EventEmitter를 사용하는 방법, Promise를 사용하는 방법 같은 것들이 있다. 아니면 타입스크립트를 쓰는 방법도 생각해 볼 수 있다. 자바스크립트는 단순성 때문에 초기 진입 장벽이 낮은 편이라서 뛰어드는 사람들이 많지만 점점 고급 프로그램을 짜게 되면 그 단순성 때문에 돌아버리게 되는 일이 십상이다. 즉 좀 더 복잡한 언어들은 대체로 고급 기능을 구현할 때에는 좀 더 쉽게 구현할 수 있게 돕는 도구들이 많지만 자바스크립트 같은 경우에는 그 단순한 것들을 잔뜩 이어 붙여서 고급 기능을 구현할 때가 많으므로 콜백 지옥과 같은 아득한 경지를 경험할 때가 종종 일어난다.

Node.js가 자랑하는 빠른 성능은 Node.js가 처리속도가 뛰어나서라기보다는 싱글스레드 기반의 비동기 처리 방식 때문이라, 이 점을 제대로 이해 못하고 프로그래밍하면 오히려 기존 웹 서버보다도 느릴 수 있다. 보통 데이터베이스디스크 입출력을 많이 하는 반면 웹 서버에서 연산을 많이 하지 않는 웹 페이지라면 Node.js가 확실히 빠르지만 그 반대의 경우라면 Node.js가 별 힘을 못 쓴다. 자바스크립트의 속도가 많이 빨라진 건 사실이지만 연산을 많이 해야 하는 작업에서는 그닥 효율이 좋지는 않다. CPU 연산을 많이 필요로 하는 부분은 C로 따로 모듈을 만들고 접착시키는 편이 낫다는 게 Node.js 개발자님의 조언. 자바스크립트 개발자한테 C 공부까지 하라니.

활용

Node.js는 기존의 강자들보다는 역사가 짧지만 정말 무서운 속도로 성장하고 있다. 사실 Node.js 자체는 뭔가 작고 소박해 보이는데, 여기에 어마어마한 모듈 군단이 가세하면서 확장성이 왕창 넓어졌다. npm 패키지 관리자는 Node.js에 어마어마한 날개를 달아주게 되는데, 중앙집중식 패키지 저장소에서 원하는 모듈을 손쉽게 검색하고 설치할 수 있기 때문에 Node.js의 활용 폭을 어마어마하게 넓혀 주었다. 다른 프로그래밍 언어도 없는 건 아니지만 패키지의 수나 성장속도가 정말 어마어마하게 빨라서 '혹시 이런 모듈 없나?' 하고 검색하면 우루루 쏟아져 나올 정도다. 또한 npm 설정 파일을 잘 만들어 두면 내 컴퓨터에서 개발했다가 웹 서버로 옮긴다든가 할 때, 설정 파일을 가져가서 npm을 돌려주면 내 웹 애플리케이션에서 사용했던 모듈을 몽땅 가져오므로 의존성 관리도 편리하게 할 수 있다.

최근 들어서는 엔터프라이즈급 서비스들이 Node.js로 이전하는 사례들이 나타나면서 더욱 주목 받고 있다. 대표적인 예가 페이팔. 유명한 PHP 기반 블로그 플랫폼인 워드프레스를 호스팅 서비스하는 WordPress.com도 2015년 칼립소 프로젝트를 공개했다. 이를 통해 PHP를 들어내버리고 Node.js 기반으로 옮겨갔다.[5] 이 과정에서 이전에는 웹 서버 쪽에서 처리하던 상당 부분을 클라이언트 쪽으로 옮겨서 SPA를 구현함으로써 웹 서버 부담을 크게 줄였다고 밝히고 있다. 한마디로 사용자에게 시스템 부하 떠넘기가. 워드프레스PHP 기반으로 가장 인기 있는 플랫폼 가운데 하나이기 때문에 WordPress.com가 Node.js 기반으로 옮겨간 것은 나름대로 큰 사건으로 받아들여졌다. 단, 사용자가 내려 받아 설치해서 쓰는 워드프레스는 여전히 PHP 기반으로 개발되고 있다.

최근에는 Node.js에 가장 인기 있는 웹 프레임워크인 Express, 여기에 자바스크립트 기반 NoSQL 데이터베이스 서버인 몽고DB, 그리고 구글이 만든 MVC 방식 클라이언트 측 자바스크립트 프레임워크인 Angular를 묶어서 MEAN 스택이라는 자바스크립트 풀 스택 플랫폼 개념이 구축되고 있고 인기 급 상승 중이다. 자바스크립트 언어 하나로 프론트엔드-백엔드-데이터베이스까지 퉁쳐버리는 것이다. 자세한 내용은 해당 항목 참조.

서버만이 아니라 데스크톱 환경으로도 폭을 넓히고 있다. 깃허브의 일렉트론 프레임워크는 Node.js 기반으로 윈도우, 맥, 리눅스에 걸친 크로스 플랫폼 프로그램 개발을 가능하게 한다. 일렉트론 기반 가장 인기있는 프로그램은 뭐니뭐니 해도 마이크로소프트의 비주얼 스튜디오 코드. 자바스크립트 기반 개발환경을 꾸밀 때에도 node.js가 설치는 거의 필수다. 프로젝트 및 기본 코드 만들기, 디버깅, 패키지 관리를 비롯한 각종 작업을 Node.js와 npm을 이용하기 때문.

설치

간단하다. 공식 웹사이트에서 운영체제별로 Node.js 서버 프로그램을 내려 받아서 설치한 다음, 명령행에서 node를 실행하면 된다, node만 실행하면 마치 파이썬 인터프리터와 같은 대화형 쉘 모드로 진입해서 명령을 입력하고 응답을 받을 수 있다. 이를 노드 REPL(Read-Eval-Print-Loop)이라고 한다. 웹 애플리케이션을 위한 자바스크립트 파일을 node 뒤에 지정해 주면 그 파일을 실행시킨다. 예를 들어, 다음과 같은 자바스크립트를 example.js로 저장하고,

var http = require('http');

http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/plain'});
  response.end('Hello World\n');
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');

명령행에서 다음과 같이 실행한다.

> node example.js
Server running at http://127.0.0.1:8124/

그리고 웹 브라우저 주소창에 http://localhost:8124라고 입력해 보면 'Hello World'라는 메시지가 보이고, 노드를 실행시킨 터미널에는 'Server running at http://127.0.0.1:8124/'라는 로그 메시지가 뜬다. 참 쉽죠? 아파치톰캣처럼 이것저것 설정하고 어쩔 필요 없이 짠 하고 내가 만든 웹 애플리케이션이 뜬다!

각주

  1. 최근 각광 받고 있는 웹 서버인 Nginx 역시 비동기 이벤트 기반이다. Nginx아파치 웹 서버가 소켓이 1만 개 이상 열리면 성능이 급격하게 저하되는 문제를 해결하기 위해 시작한 프로젝트다.
  2. 예를 들어 웹 페이지에 사진 이미지가 있다면 이것도 웹 서버 어딘가에 있는 파일을 다운로드하는 것이다.
  3. 백엔드에 다른 언어를 써도 가능하지만 프론트와 백에 같은 언어를 쓰게 되면 구현 과정의 일관성 면에서도 좋고 접착도 잘 되는 편이다.
  4. 윈도우 NT 커널 기반 이전인 윈도우 3.0이나 윈도우 95와 같은 경우에 비슷한 문제가 있었다. 말은 멀티태스킹이지만 실제로는 개별 프로그램이 자원을 사용한 다음에 돌려주는 식으로 구현하다 보니 프로그램에서 이걸 잘못 처리해서 안 돌려주면 전체 시스템이 먹통이 될 수도 있었다.
  5. https://developer.wordpress.com/calypso/