- 개발 생산성이 좋아?
- 성능이 좋고 안정적이야?
- 개발자 커뮤니티는 활발해?
그리고 Node.js를 사용하기로 결정한 뒤로 식당, 펜션, 항공권, 호텔 등 여러 서비스를 Node.js로 개발했습니다.
아마 많은 개발자가 Node.js를 서비스에 적용할까 말까 고민하고 있을 듯합니다. 이 글에서는 이런 개발자들을 위해 그동안의 경험과 자료를 바탕으로 위의 세 가지 질문에 대한 답을 정리했습니다.
이 글은 Node.js를 소개하는 글은 아닙니다. Node.js가 궁금하신 분은 웹을 검색해 보세요. 이미 많은 자료가 있습니다.
개발 생산성
개발 생산성이 좋으면 개발 과정에 들어가는 비용과 노력을 줄일 수 있다. JavaScript를 기반으로 하는 Node.js는 풀스택 개발, JSON 사용, 비동기 프로그래밍 등을 가능하게 해 개발 생산성을 높일 수 있다.
의사소통 비용을 줄이는 풀스택 개발
다음은 프런트엔드 개발자와 백엔드 개발자가 주고받는 이야기다.
"API 파라미터에 이 필드값이 변경됐어."
"API 응답 결과에 이거 넣어 줘."
"얘기도 안 하고 변경하면 어떡해."
프런트엔드 개발자와 백엔드 개발자가 다르면 서로 필요한 일, 구현한 일을 공유할 때 의사소통 비용이 발생한다. 한 개발자가 프런트와 백엔드를 모두 개발하는 풀스택 개발에는 이런 의사소통 비용이 필요 없다. Node.js를 사용하면 프런트엔드 개발자가 비교적 쉽게 백엔드 개발까지 할 수 있다. Node.js의 개발 언어는 JavaScript니까.
프런트엔드 개발자가 백엔드를 개발하면 전문성이 모자라 개발에 깊이가 없다는 우려도 있다. 맞는 이야기일 수 있다. 하지만 요즘 요구하는 백엔드 개발에서 깊이는 이전과 다르다. 많은 기능이 추상화돼 있어 이전보다 쉽게 백엔드를 구현할 수 있다.
Facebook이 인수한 Parse가 그 사례다. Parse에서는 JSON 문서 하나만 정의하면 CRUD API가 그냥 제공된다.
코드의 양을 줄이는 JSON 지원
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 명세 적용
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 정도로 충분하다고 생각한다.
개발자 커뮤니티
Node.js를 활용하는 개발자가 많을수록 여러 문제의 해결책을 쉽게 찾을 수 있고 활용할 수 있는 오픈소스도 많아진다.
Node.js의 급부상은 개발자를 대상으로 2015년에 진행한 Stack Overflow의 설문 조사에서 확인할 수 있다. 설문 조사 결과에 따르면 Node.js의 인기도가 매년 상승했다. 이렇게 매년 인기도가 상승한 언어는 Angular.js와 Node.js뿐이다. 범용 프로그래밍 언어와 비교했을 때도 Node.js는 서버 플랫폼으로서 높은 인기도를 얻었다. 또한 Node.js 개발자의 연봉 수준이 미국을 기준으로 했을 때 2위에 올랐다.
Node.js의 패키지 시스템인 npm의 사용자 통계도 인상적이다. 주당 10억 회 이상에 이를 정도로 패키지 다운로드 횟수가 폭발적으로 증가하고 있다. 등록된 npm 패키지 개수도 73,000개에 이른다. 경험상 웬만한 기능은 이미 다른 개발자가 npm 패키지로 구현해 놓았다.
개발과 운영 도구
지금까지 Node.js를 사용하기 전에 고민했던 세 가지 선택 기준인 개발 생산성, 성능과 안정성, 커뮤니티 활성화 정도를 살펴봤다. 이 기준에 맞춰 Node.js를 사용하기로 결정했고 지금까지 안심하고 사용하고 있다.
이제 그동안 Node.js로 서비스를 개발하고 운영하면서 사용한 도구를 소개하겠다.
보일러플레이트
프로젝트를 처음부터 완전히 새로 작성하는 것보다는 일종의 프로젝트 템플릿인 보일러플레이트를 활용하는 것이 훨씬 효율적이다. JavaScript에는 Yeoman이라는 보일러플레이트 생성 도구가 있다. 다양한 생성기가 있으니 인기도가 높은 것을 선택해 사용한다.
빌드 도구
프로젝트를 빌드하는 도구로는 webpack, gulp, Grunt 등을 사용한다. 최근에는 webpack 사용자가 늘어나고 있고, Grunt 사용자는 줄어들고 있다.
데이터 저장소와 연동
데이터 저장소별로 Node.js를 연동할 때 사용할 수 있는 여러 도구가 있다.
- MongoDB 연동: Mongoose
- Elasticsearch 연동: elasticsearch.js
- MySQL 연동: node-mysql
- Redis 연동: node_redis
일괄 작업 관리
일괄 작업(batch)을 관리할 때는 node-cron, Node Schedule, Agenda 등을 사용한다.
배치 스크립트
일괄 작업을 실행하는 배치 스크립트는 gulp의 스크립트 파일을 작성해 실행한다.
템플릿 엔진
템플릿을 사용해 웹 페이지를 구성할 때는 Jade, mustache.js 등의 템플릿 엔진을 사용한다.
프로세스 관리
Node.js의 프로세스를 관리하는 도구로는 PM2를 추천한다.
PM2를 사용하면 Node.js 프로세스를 여러 개 실행할 수 있다. Node.js에도 프로세스를 여러 개 실행하는 기능이 있지만 추가 코딩이 필요하다.
PM2에는 프로세스가 중지되면 프로세스를 다시 실행하는 기능도 있다. 그 외에 프로세스별로 CPU와 메모리 사용량을 모니터링할 수도 있다.
참고로, 보통 Node.js 프로세스의 개수는 CPU 코어의 개수로 한다. 메모리 용량은 'Node.js 프로세스의 개수 x 1GB'로 넉넉하게 한다. Node.js처럼 메모리 관리를 자동으로 하는 플랫폼을 사용할 때는 메모리 용량이 커야 한다.
마치며
인터넷 서비스는 사용자의 요구에 빠르게 반응하는 것이 중요하다. 생산성이 높은 Node.js는 인터넷 서비스 개발에 사용할 수 있는 좋은 도구다.