Why Node.js?

웹 시스템 설계 과목의 중간고사를 위해서 Node.js의 특징들을 그렇게 열심히 공부하고도 누군가 나에게 자바스크립트와 노드를 쓰는 이유, 비동기프로그래밍의 설명에 대해 물었을 때 시원하게 답을 하지 못했다.

node-js_logo-svg


왜 Node.js 일까?

Node.js는 JavaScript V8 엔진 위에서 동작하는 I/O Framework다. 내장 HttpLibrary를 포함하고 있어 웹서버로써의 기능을 구현할 수 있으며 자바스크립트를 서버 사이드 스크립트로 사용한다.

개발 생산성

Node.js 서버를 구성함으로써 클라이언트 사이드와 서버 사이드가 같은 언어로 작성될 수 있다. 특히 구글 크롬의 V8 엔진을 사용했다는 것이 이런 장점을 더욱 극대화 한다. 이에 따라 한명의 개발자에 의한 Feature별 풀스택 개발이 더 쉬워졌다. 한명이 풀스택 개발을 하지 않더라도, 클라이언트 개발자 간의 의사소통이 훨씬 쉬워진다는 것은 생산성 향상에 큰 영향을 준다. PayPal 또한 Node.js로의 서버 전환이 개발 생산성 향상을 위함이라고 밝혔다.

오픈소스 커뮤니티

Node.js의 공식 홈페이지에는 npm을 기반으로한 노드의 오픈소스 커뮤니티가 세계에서 가장 큰 라이브러리 생태계라고 한다. 정확한 팩트 체크는 못했지만 적어도 파이썬에 버금간다는 것은 확실하다.

성능과 안정성

PayPal도 사용하고 있는 Node.js 서버는 안정성과 성능을 입증했다. Paypal의 내부 실험 결과 요청처리와 응답시간에서 Node.js가 Java보다 빠른 성능을 보였다.

Event-Driven I/O와 Asynchronous Programming

Node.js 가 이러한 빠른 성능을 보이는 이유는 Thread 기반의 I/O가 아닌 비동기적 프로그래밍을 기반으로 Event-Driven I/O를 지원하기 때문이다.


Asynchronous Programming

코드가 짜여진 순서대로 실행되는 것을 Synchronous Programming이라고 할 수 있다. 어떤 코드가 다 실행된 후에야 그 다음 코드가 실행된다. 하지만 자바스크립트는 비동기적 프로그래밍을 지원한다. 코드의 실행순서가 동기화 되어있지 않다. 이는 Callback 함수의 활용을 통해 구현된다. Callback 함수는 어떠한 이벤트에 의해 실행되는 함수이다. 보통 이벤트 리스너로 등록되거나 CPU를 사용하지 않는 함수의 인자값으로 전달되어 사용된다.

Callback과 Event-Driven I/O

스크린샷 2016-11-24 오후 10.01.16.png

위 그림은 Thread model과 Event-Driven model의 비교이다. Thread model(왼쪽 위)은 하나의 Request에 대해 하나의 쓰레드를 할당하여 그에 대한 Response까지 책임진다. 이 과정에는 CPU를 필요로 하지 않는, 예를 들면 DB, File I/O 등, 작업 처리도 해당 Thread의 책임과정에 포함되고, 이는 CPU 낭비를 발생시킨다. 또한 Request가 폭발적으로 증가할 경우, 머신이 감당할수 있는 Thread의 수를 벗어나는 경우가 발생할 수 있다.

Event-driven model은 모든 요청을 EventQueue에 넣고 이를 Single thread가 순서대로 처리한다. 이 과정에서 Open, Read, Send / Connect, Query, Send와 같이 CPU가 그 결과를 기다려야하는 일 A을 처리할때, 이 Single thread는 이를 기다리지 않고 다음 작업 B, C, D, E를 실행한다. A가 끝나고 결과 값이 리턴되면 Event를 발생시키고 이는 Event Queue에 들어가 자신의 순서가 되면 그 결과값을 처리한다. 이 Event Queue에 들어가는 작업, A가 끝남으로써 발생한 Event에 의해 호출되는 작업을 Callback 함수를 통해 전달하는 것이다.

스크린샷 2016-11-24 오후 10.09.43.png

이러한 일을 수행하는 Single thread를 이벤트 루프라 한다. 이벤트 루프는 비동기 프로그래밍과 이벤트 큐를 활용하여 CPU 낭비 없이 유저 요청을 빠르게 처리할 수 있다. 그러나 이벤트 루프가 어쩔수 없이 멈춰야 하는  Blocking call을 사용할 때는 내부의 Thread pool에서 Thread 하나를 꺼내와 해당 작업을 할당하고 이에 대한 결과 역시 이벤트 발생과 콜백 함수를 통해 처리한다. 이를 통해 Node.js는 CPU의 낭비를 줄이고 적정 수의 Thread를 활용하며 빠른 성능과 안정성을 보장한다.

Single, Single Thread

그러나 수많은 유저로 부터의 요청을 하나의 Thread가 처리한다는 것은 Node.js가 갖고 있는 부담감이다. 불필요한 I/O 대기 시간을 줄이는 것으로 속도를 향상시켰지만, 같은 요청에 대한 CPU 연산량을 줄이는 것은 아니다. 이러한 CPU 연산이 길어지며 하나의 요청을 처리하는 응답시간이 길어지면 다음 요청이 처리되지 못하고 기다려야 한다. 이 경우 오히려 성능 저하를 일으키는 것이다. 따라서 Node.js는 과도한 CPU작업을 요구하는 작업에는 적합하지 않다. 그러나 이에 대한 해결책으로 Celery 등의 disributed task queue를 사용하여 과도한 CPU 연산 부하를 분산시킬 수 있다.

사진: 실버라이닝 플레이북, 구글이미지, 아주대학교 웹시스템설계 강의노트/오상윤 교수님

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중

search previous next tag category expand menu location phone mail time cart zoom edit close