Node.js 프로젝트가 마침표에 가까워질 수록 프로세스를 어떻게 관리해야 할지 고민한다. 요즘은 Node.js Domain API에 완전히 당해서 넋이 나가 있었다.


PM2 로 App 을 시작 할 때 Debug Log를 감시하고 싶을 때가 있다. 아이러니하게도 node debug로 사용된 로그는 stderr 로 출력된다.



stdout 으로 출력하기 위해서는 환경변수를 추가해야 한다.


DEBUG_FD=1


아래는 pm2 설정 JSON 이다. 취향에 따라서 직접 명령으로 실행해도 무관 하다.


  • pm2-test.json
{
    "apps": [
        {
            "name"             : "test-app",
            "script"           : "./test.js",
            "error_file"       : "./logs/app/test-app.stderr.log",
            "out_file"         : "./logs/app/test-app.stdout.log",
            "pid_file"         : "./pids/test-app.pid",
            "instances"        : 0,
            "min_uptime"       : "1000s",
            "max_restarts"     : 15,
            "watch"            : false,
            "ignore_watch"     : ["[\\/\\\\]\\./", "node_modules"],
            "merge_logs"       : true,
            "exec_interpreter" : "node",
            "exec_mode"        : "cluster_mode",
            "autorestart"      : false,
            "vizion"           : false,
            "env"              : {
                "NODE_ENV"     : "development",
                "DEBUG"        : "*",
                "DEBUG_FD"     : 1
            }
        }
    ]
}


명령어를 실행 시 node debug로 사용된 로그는 stdout 으로 출력된다.


pm2 start pm2-test.json



정상적으로 출력 되는 것을 확인 할 수 있다.


'Nodejs' 카테고리의 다른 글

NPMv3 사용하기  (0) 2016.04.04
Node.js와 ECMAScript 2015 (ES6)  (0) 2016.01.04
Node.js NPM Previous Version 설치 하기  (0) 2015.12.08
play.node(2015) 후기  (0) 2015.11.13
Nodejs Express 4.x File Upload 설정 하기  (0) 2015.02.10

Node.js release - https://nodejs.org/en/download/releases/


위 링크는 node.js release 내역이다. windows 환경에서 Node.js v4.x.x, v5.x.x를 번갈아 설치 하다 보면, npm 버전이 3.x.x으로 고정되는 현상이 발생한다. 처음에는 방법을 몰라서 몇 번이고 재설치를 해보았지만, 바보 같은 시도였다. 초심으로 돌아가서 생각해보니 npm 으로 재설치 하면 될까 하는 방법이 떠올랐다.


$ npm -v
3.3.10

$ npm install npm@2.14.7 -g

$ npm -v
2.14.7


npm install {app}@{version}


  • app: 설치 할 앱
  • version: 설치 할 버전

위와 같이 설치 하면, node.js 재 설치 없이, 원하는 버전을 설치 할수있다.




상기 내용에 대한 저작권은 play.node 에 있습니다.


play.node(2015) 후기입니다. 좋은 경험을 할 수 있게 기회를 주신 회사에 감사드립니다.

1. Node.js LTS/Stable





Node.js 는 초창기에 v1.0 이 과연 언제 나올까 기다리는 게 큰 이슈였습니다. 불미스럽게도 node.js 를 fork 로 시작한 io.js 가 나오게 되고 나뉘어 가는 행보를 보였으나, 결국 통합되어 v4.0.0 이 나오게 됩니다. 


기존에는 stable, unstable 정책으로 관리 되었으나, 이번에 새롭게 변경되었습니다.


LTS는 짝수 버전에 해당하며, 안정화, 호환성에 초점을 맞춘 버전이고, stable는 새로운 기능이 활발하게 개발되는 버전입니다.


위 그림은 해당 내용에 대한 버전 일정 이며, 기업에서는 미리 버전 업데이트 일정을 정해서 대비할 수 있습니다.


Node.js 소식은 http://nodejs.github.io/nodejs-ko/ 에서 번역본을 볼 수 있습니다. 번역 까지는 최소 2주 정도 걸린다고 합니다.


2. Node.js Module - (NodeSource/Tim Oxley)


Javascript로 작성되는 프레임워크는 수명이 짧다고 합니다. 해당 언어로 구성된 Node.js 생태계는 격동하는 모습을 보여주고 있고, 프레임워크에 의존하게 되면 새로운 버전이 나왔을 때 맞추어 갈 수 없는 상황이 나오기도 합니다. 예를 들어 C/C++ 로 작성된 모듈이 버전 업데이트를 했을 때 동작하지 않는 경우도 있었다고 합니다. 프레임워크를 도입한다면, 고질적인 문제를 항상 고려해야 합니다.




Node.js 는 프레임워크 보다 상대적으로 모듈화 문화를 적극적으로 지지하고 있고, Node Package Manager(NPM)의 total packages는 공식 홈페이지 2015/11/13 기준 204,841 개입니다.



각 언어의 설치 패키지 pip, gem, maven 등을 합친 수보다 많다고 합니다. 수가 많은 만큼 사용되지 않는 라이브러리도 많으므로, 선점 할때, commit 날짜, 다운로드 수, 버전에 대한 정보는 확인합니다.


실제 애플리케이션을 개발할 때는 라이브러리 개발과 다소 차이가 있다고 합니다. 라이브러리는 단순하면서 사용하기 편해야 합니다. 애플리케이션은 고객의 비지니스를 만족해야 합니다. 개발할 때 자신도 모르게 복잡성 안에 함몰된 있는 모습을 발견합니다. 발표자는 Over Engineering 이라고 표현합니다. 무리한 요구사항이 들어와서 이를 적용해야 하는 데, flat 한 구조, 설계가 된 구조 애플리케이션이 있다고 가정하면, 후자가 훨씬 비용이 많이 들어가게 됩니다. 무리한 설계는 안 하는 좋습니다.


Javascript는 문제가 발생했을 때 해결을 쉽고 빠르게 할 수 있다는 장점이 있습니다. 하지만 끝나지 않는 숙제가 있습니다. 중첩 Callback, 비동기 코드이기 때문에 결과 예측이 쉽지 않습니다. 발표자는 수직적인 구조 사용을 자제하고, flat 한 구조를 권장하고 있습니다.


모듈화를 할수록 Local 복잡도는 감소하는 대신 Global 복잡도는 증가합니다. 최대한 단순하게 개발하고 지나친 모듈화는 피해야 합니다.


3. Node Package Manager [NPM V2 -> NPM V3] - (npm inc/Kat Marchan)




Package Magager 의 Node.js 버전입니다. 흔히 많이 알고 있는 pip, gem, maven과 비슷합니다. 앞에 Node를 붙여 약자로 NPM 이 됩니다.


불편한 점, 버그는 github, twitter 로 개발자들이 문의합니다. NPM V2 중 제일 많았던 문의는 dependence tree입니다. “npm install package” 명령어로 설치를 진행합니다. 각 패키지별 dependence 도 존재 하는 데, 각각 관리를 하므로 중복되는 package가 많고, 규모가 작은 애플리케이션이면 무시할 수 있는 수준이지만, 규모가 커진 경우 애플리케이션 용량이 큽니다. NPM V3 에서는 기능 개선을 하여 각 패키지 dependence 의 중복을 제거하여 기존에는 하위에 하위 폴더로 가는 구조였다면, 같은 선상에서 package가 설치됩니다. 중복을 제거하는 대신 안정화 된 버전의 패키지가 설치되어야 하므로 버전 규칙에 대해 강조 하였습니다.


설치 시 진행 상황을 알고 싶어하는 요청이 있어 NPM V3 에서는 설치 시 Progress Bar를 지원합니다.




npm 다운로드 유저중 42%는 윈도우 개발자이기 때문에 지원을 아까지 않는다고 합니다.


NPM V3 은 Node.js v5.0.0 이상부터 지원합니다.


4. Callback Hell


동기 방식은 차례로 진행되지만, 비동기 방식은 동시에 실행이 되기 때문에 끝났다는 신호를 줘야 합니다. 그 신호가 일명 Callback입니다.


비동기 방식을 동기 방식처럼 개발하기 위해 많은 노력이 있었습니다.


이를 극복하는 라이브러리에 대한 소개입니다.


async

  • 순차 혹은 병렬 실행 지원
  • 어지간한 경우에 쓸만 합니다.

promise

  • ES6 표준에 포함
  • async와 비슷하나 좀 더 깔끔한 코드
  • 병렬 실행이 가능합니다.
  • 예외 처리가 역시 쉽습니다.

출처



Express 가 4.x 이 되면서 Connect 라이브러리를 사용하지 않는다. 프로젝트 생성시에도 body-parser, cookie-parser 를 추가로 설치 해줘야 한다.


파일 업로드 하는 부분에 있어서도 별도의 미들웨어를 사용해야 한다. 간단하게 사용할 수 있는 Multer 를 소개 한다.



설치 시 --save 옵션을 사용하게 되면 package.json 에 추가되어 다른 환경에 설치 시 npm install -d 로 일괄 설치 할 수 있다.


$ npm install multer --save


app.js 에 미들웨어 선언을 하자.


var app = express()
app.use(multer({ dest: './uploads/'}))


파일 업로드 시 아래의 객체에서 확인이 가능 하다.


console.log(req.body)
console.log(req.files)


자세한 내용은 github 를 참조 하도록 하자.


불과 몇 개월 사이에 Node 설치 방법이 참 편리해 졌다.


Nodejs 설치 하기 - http://blog.whitelife.co.kr/85


직접 의존성 라이브러리, Nodejs 를 수동으로 설치 했다. 자세한 글은 위 주소를 참고하자. 금주에 설치 할 일이 있어 조언도 받고, 검색도 해보았다.


Node Version Manager - https://github.com/creationix/nvm


  • Install script (Linux 기준)
curl https://raw.githubusercontent.com/creationix/nvm/v0.19.0/install.sh | bash
git clone https://github.com/creationix/nvm.git ~/.nvm && cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`
source ~/.nvm/nvm.sh

  • Usage
nvm install 0.10
nvm use 0.10


정말 간단하다. 위 명령어를 따라 실행 하기만 하면 된다.



npm global 설치 시 주로 발생 한다. 


centos 기준 /usr/local/lib/node_modules 폴더 접근 권한이 없기 때문에 root 권한을 줘야 한다.


sudo npm install -g [package name]


root 에서는 node 명령어를 못찾는 경우가 있다. 그럴 경우


sudo ln -s /usr/local/bin/node /usr/bin/node
sudo ln -s /usr/local/lib/node /usr/lib/node
sudo ln -s /usr/local/bin/npm /usr/bin/npm


위 명령어를 추가 한 후 사용 하자.



Node.js 요즘에 주목 받고 있는 언어 같다.


Node.js 는 자바스크립트, 구글 V8 엔진을 사용 하는데, 자바스크립트는 개발자들에게 익숙한 언어이고, 웹 애플리케이션 서버 개발시 직접 구현도 가능 하지만 Expressjs 라는 대표적인 웹프레임워크를 많이 사용 하는 편이다.


전화통화로 몇일 전 위 이유 때문에 많이 사용 하지 않을까? 라고 말했던 형도 있었다.


Express 공식 사이트


여기서 한가지 짚고 넘어갈 것이 있다.


Node 공식 사이트 소개 글 

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.


위 내용을 보자면 쉽게 확장이 가능한 네트워크 애플리케이션을 구축 하기 위한 플렛폼이고, 추가적인 기능으로 이벤트 기반, non-blocking I/O 를 지원 한다.


웹프레임워크로 상대적으로 쉽게 개발을 하기 때문에 망각 할 수 있지만, 기억하고 있어야 할 부분이라고 본다.


Node.js 기반으로 만들어진 놀라운 10가지 프로젝트가 있다. 그냥 읽고만 넘기기엔 내용이 좋다고 판단이 되어 글을 남겨 본다.


이거 정말 필요할 것 같다. 라고 생각 된건 두 가지!! 


실제 개발이 완료 된 후 운영에 들어간다면 데스크톱 애플리케이션 처럼 사용하면서 정보를 가공할수 있는 Node-Webkit, 서버 로그 관리 차원에서 훌륭한 도구가 될 Log.io 보고 와~ 했다.


  [그림 1] log.io 공식 페이지


틈틈히 한번씩을 사용해봐야 겠다. 먼가 도움이 많이 될거 같다.


※ 참고 사이트

  - http://nodejs.org/

  - http://www.itworld.co.kr/slideshow/85221




Express middleware는 Java 진영의 Springframework의 interceptor, aop 와 비슷한 성향을 가지고 있습니다.



위 그림을 참고 해보자.


서버로 요청이 들어오면 middleware 는 route / 모든 주소에 대해서 처리하라는 지시를 받습니다. 그 후 특정 url 에 대해서 처리를 한 후 응답을 하게 됩니다.


실제로 log를 확인해 봤습니다.


app object 중 stack

  stack: 
   [ { route: '', handle: [Function: query] },
     { route: '', handle: [Function: expressInit] },
     { route: '', handle: [Function: logger] },
     { route: '', handle: [Function: cookieParser] },
     { route: '', handle: [Function: bodyParser] },
     { route: '', handle: [Function: methodOverride] },
     { route: '', handle: [Function: test] },
     { route: '', handle: [Function: session] },
     { route: '', handle: [Function] },
     { route: '', handle: [Function] },
     { route: '', handle: [Function: router] },
     { route: '', handle: [Function: errorHandler] } ]


app object 중 router

_router: 
   { map: 
      { get: 
         [ { path: '/test/test',
             method: 'get',
             callbacks: [ [Function] ],
             keys: [],
             regexp: /^\/test\/test\/?$/i },
            ....
         ],
         post: 
         [ { path: '/test/test',
             method: 'get',
             callbacks: [ [Function] ],
             keys: [],
             regexp: /^\/test\/test\/?$/i },
            ....
         ]
      }
   }


서버로 request가 들어오는 이벤트가 발생할 경우 stack 을 통과하게 됩니다. 

개발자가 직접 정의 하는 middleware 는 test 라는 함수이고, 모든 url 처리는 stack 를 통과하고 특정 url은 router 에게 처리를 위임 하게 됩니다. 실제 code를 보도록 하자.


./express/lib/application.js 중 일부 입니다.

/** * Proxy `connect#use()` to apply settings to * mounted applications. * * @param {String|Function|Server} route * @param {Function|Server} fn * @return {app} for chaining * @api public */ app.use = function(route, fn){ var app; // default route to '/' if ('string' != typeof route) fn = route, route = '/'; // express app if (fn.handle && fn.set) app = fn; // restore .app property on req and res if (app) { app.route = route; fn = function(req, res, next) { var orig = req.app; app.handle(req, res, function(err){ req.app = res.app = orig; req.__proto__ = orig.request; res.__proto__ = orig.response; next(err); }); }; } connect.proto.use.call(this, route, fn); // mounted an app if (app) { app.parent = this; app.emit('mount', this); } return this; };

"default route to '/'" 내부적으로 기본 값으로 설정이 되는 것을 확인 할 수 있습니다. 


이제 실제 사용법을 알아보도록 하자.



http://expressjs.com/api.html#app.use 공식 홈페이지 Reference 자료 입니다.

두번째 인자로 function 이 사용 됩니다.


위 자료를 참고 하여 Sample Code 작성 해보자.

함수형으로 return 하자.

function test() {
  return function test(req, res, next) {
    console.log('test');   

    next();
  }
}

next() 는 stack 의 다음 주소로 가라는 함수 입니다. 실제로 next() 를 호출 하지 않는 경우 응답을 하지 못하고 서버에서 멈춰버리게 됩니다.


app.js 설정의 일부 입니다. 실제로 적용 하자.

function setting() {
  app.configure(function(){
    app.set('port', process.env.PORT);
    app.use(express.logger('dev'));
    app.use(express.cookieParser());
    app.use(express.bodyParser());
    app.use(express.methodOverride());

    // user middleware
    app.use(test());
    
    // session config
    app.use(express.session({
      secret: config.redis.secret,
      store: new RedisStore(config.options),
      cookie: config.cookie
    }));

    app.use(passport.initialize());
    app.use(passport.session());

    // router
    app.use(app.router);
  });  
}

use 함수 호출 하는 부분을 볼 수 있는데, 해당 행위는 모든 요청에 대해서 처리를 하겠다는 말입니다. 

위와 같이 적용 하면 모든 요청에 대해서 test 함수가 호출 되는 것을 확인 할 수 있습니다.


※ 참고 사이트: http://expressjs.com/


+ Recent posts