Node.js는 확장성 있는 네트워크 애플리케이션(특히 서버 사이드) 개발에 사용되는 소프트웨어 플랫폼이다. 작성 언어로 자바스크립트를 활용하며 Non-blocking I/O와 단일 스레드 이벤트 루프를 통한 높은 처리 성능을 가지고 있다. 내장 HTTP 서버 라이브러리를 포함하고 있어 웹 서버에서 아파치 등의 별도의 소프트웨어 없이 동작하는 것이 가능하며 이를 통해 웹 서버의 동작에 있어 더 많은 통제를 가능케 한다.
JavaScript
V8 엔진
고성능 네트워크 서버
Single Thread
Event Loop
비동기(Non-blocking) I/O 처리
개발 생산성 향상
NPM
방대한 모듈 패키지
Nexflix : 서버 자원 관리 효율성, 페이지 로딩 성능 향상
PayPal : Java 5명 vs Node 2명으로 서비스의 프로토타입을 만들게 했더니 Node쪽이 더 빠르게 구현. 5명이 필요한 일을 2명이 할 수 있게 되는 경우 (생산성 향상)
Linked, Walmart : 작은 서버로 대규모트래픽을 더 빠른 서비스 제공
출처 https://junspapa-itdev.tistory.com/3
개발 생산성이 좋으면 개발 과정에 들어가는 비용과 노력을 줄일 수 있다. JavaScript를 기반으로 하는 Node.js는 풀스택 개발, JSON 사용, 비동기 프로그래밍 등을 가능하게 해 개발 생산성을 높일 수 있다.
"API 파라미터에 이 필드값이 변경됐어." "API 응답 결과에 이거 넣어 줘." "얘기도 안 하고 변경하면 어떡해."
프런트엔드 개발자와 백엔드 개발자가 다르면 서로 필요한 일, 구현한 일을 공유할 때 의사소통 비용이 발생한다. 한 개발자가 프런트와 백엔드를 모두 개발하는 풀스택 개발에는 이런 의사소통 비용이 필요 없다. Node.js를 사용하면 프런트엔드 개발자가 비교적 쉽게 백엔드 개발까지 할 수 있다. Node.js의 개발 언어는 JavaScript니까.
프런트엔드 개발자가 백엔드를 개발하면 전문성이 모자라 개발에 깊이가 없다는 우려도 있다. 맞는 이야기일 수 있다. 하지만 요즘 요구하는 백엔드 개발에서 깊이는 이전과 다르다. 많은 기능이 추상화돼 있어 이전보다 쉽게 백엔드를 구현할 수 있다.
Facebook이 인수한 Parse가 그 사례다. Parse에서는 JSON 문서 하나만 정의하면 CRUD API가 그냥 제공된다.
Node.js는 비교적 코드의 양이 적다. JavaScript 언어 자체가 JSON을 지원하기 때문이다. JSON은 오늘날 데이터 표현을 위한 실질적 표준이다. 응용 코드의 상당 부분이 데이터 처리임을 고려할 때 이는 Node.js의 큰 장점이다.
데이터 저장소로 MongoDB나 Elasticsearch를 사용하면 이 장점은 더욱 강해진다. 데이터의 저장부터 노출까지 모든 레이어에 걸쳐 JSON 형식으로 데이터 표현이 통일된다. 다른 플랫폼에서 필요한 ORM이나, 객체와 JSON 사이에 변환이 없어도 된다.
다음은 /user라는 API를 구현한 코드다. MongoDB에서 전체 사용자 정보를 조회해 클라이언트에 전달한다. 정말 간단하지 않은가?
app.get('/user', function(req, res) { // Return all the users to a client User.find({}, function(err, result) { if (err) throw err res.json(result) }); });
비동기 프로그래밍은 Node.js의 특징으로 종종 언급된다. 비동기 프로그래밍은 성능 면에서 매우 좋으나 코딩하기는 어려웠다. 콜백 함수를 사용해 비동기 프로그래밍을 하던 시절에는 콜백 지옥이라 할 만큼 비동기 프로그래밍의 코드가 복잡했다. 그래서 비동기 프로그래밍은 입문자에게는 진입 장벽이기도 했다.
Node.js가 지난 몇 년 간 개선되면서 이제 비동기 프로그래밍을 동기 프로그래밍만큼 쉽게 할 수 있게 됐다. async/await 함수는 비동기 프로그래밍 코드를 동기 프로그래밍 코드처럼 작성할 수 있게 한다.
다음은 async/await 함수로 비동기 프로그래밍을 구현한 예다. 세 개의 I/O를 동시에 실행하고 그 결과를 sites 배열 변수에 저장한다. I/O가 모두 완료되면 배열에 저장된 실행 결과를 콘솔에 출력한다. 코드가 정말 간단하지 않은가?
let RP = require("request-promise"); let sites = await Promise.all([ RP("http://www.naver.com"), RP("http://www.google.com"), RP("http://www.yahoo.com") ]) console.log(sites)
비동기 프로그래밍의 장점은 성능에만 그치지 않는다. 멀티스레드에서 골칫거리였던 동기화, 교착 상태(deadlock)에 대한 고민을 없애 준다. 위 코드를 멀티스레드로 구현했다면 sites 배열에 대한 동기화 코드가 필요했을 것이다.
JavaScript는 언어적으로 논란이 많았고, 이는 Node.js 사용을 주저하게 하는 요인이기도 했다. 2016년 기준으로 가장 최근 표준 명세인 ECMAScript 2015는 클래스, 화살표 함수(arrow function), 블록 단위 변수 스코프, 상수, 템플릿 문자열 등 많은 부분을 개선했다. async/await 함수는 ECMAScript 2017 표준에 포함될 예정이다.
현재 Node.js 재단에서 추천하는 Node.js 4 버전은 ECMAScript 2015의 모든 기능을 지원하지는 않는다. async/await 함수도 지원하지 않는다. 하지만 트랜스파일러인 Babel을 사용하면 ECMAScript 2015와 async/await 함수를 활용할 수 있다. Babel은 ECMAScript 2015 코드를 Node.js 4가 이해할 수 있는 ECMAScript 5 코드로 변환한다. async/await 함수 코드도 Node.js 4가 이해할 수 있게 변환한다.
Node.js의 성능과 안정성은 걱정하지 않아도 된다. PayPal, Netflix, LinkedIn, Groupon 등 전 세계적인 서비스에서 이미 Node.js를 사용한다. 네이버도 Node.js를 사용해서 초당 5천 건가량의 질의를 24-코어 서버 4대로 처리한다.
내부 실험에서는 Node.js가 Apache보다 좋은 성능을 보였다. 비동기 I/O가 멀티스레드보다 좋은 성능을 보이는 것은 당연하다. PayPal의 실험에서는 요청 처리 속도와 응답 시간에서 Node.js가 Java보다 좋은 성능을 보였다.
Node.js가 특별히 원인을 알 수 없는 이유로 종료된 경우는 없었다. Node.js가 갑자기 종료된 원인은 모두 예외 처리를 하지 않는 등 개발자 실수였다.
Node.js의 또 다른 장점은 빠른 실행이다. 프로세스가 종료돼도 1~2초면 프로세스를 다시 실행시킬 수 있다.
Node.js의 단점으로 타입이 없는 JavaScript 언어의 특성을 이야기하곤 한다. 타입이 있다면 컴파일 시점에 오류를 어느 정도 걸러 낼 수 있다. 그래서 Node.js 서버는 Java 서버에 비해 안정성이 떨어진다고 이야기한다. 맞는 이야기일 수 있다. 그러나 Node.js를 사용해서 DBMS나 검색 엔진과 같은 복잡한 소프트웨어를 개발하지는 않는다. 대부분의 응용 서버는 API와 비즈니스 로직을 제공할 뿐이다. 이런 기능은 JavaScript 정도로 충분하다고 생각한다.