Node.js 로 작성한 서버 프로그램을 Linux 에 daemon 으로 실행하기

myservice 라는 daemon 을 만드는 예제

/etc/systemd/system/myservice.service 이름으로 아래의 내용을 넣는다.

[Unit]
Description=myservice-daemon
After=network.target

[Service]
ExecStart=/usr/bin/node app.js
Restart=on-failure
User=myservice-user
Group=myservice-group
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/some/nodejs/myservice

[Install]
WantedBy=multi-user.target

아래 명령으로 방금 작성한 파일을 systemd 에게 읽도록 한다.
daemon 을 실행한다.
시스템이 부팅될 때 자동으로 실행되도록 활성화 시킨다.

systemctl daemon-reload
systemctl start myservice
systemctl enable myservice

이런 것도 필요하신가요? Node.js v0.10.36 API Doc WinHelp

Node.js 가 최근에 v0.12.0으로 업데이트 되었습니다.
그런데 이전에 사용하던 몇가지 모듈과 호환이 되지 않아 사용할 수 없는 상황이네요.

매번 웹에서 API를 확인했는데 이제 웹 문서가 업데이트 버전에 맞춰져, 온라인으로 문서 보는 건 포기
이전 버전의 markdown 문서를 받아 doxygen으로 만들었습니다.

Windows 사용하시는 분께는 편리한…
하지만 Linux 사용하시는 분들께는 미안한…
CHM 포맷으로 만들었습니다.

cfile23.uf.267467385501C6EC0185C9.7z

뭔가 문제가 있나봐요… 그리고… 마크다운을 그냥 doxygen으로 바꿨더니 불편하네요.

html 파일 버전도 추가합니다.

cfile23.uf.267DCF505508622A019879.zip

Node.js에서 cluster 사용시 디버깅

v0.10.36 이 버전에서 cluster 모듈을 사용한 어플리케이션을 –debug 옵션으로 실행하면 fork() 된 worker 들도 같은 debug port를 사용해서 오류가 발생합니다. 그래서 디버깅을 위해 몇가지 작업을 했었는데…


cluster.setupMaster()를 통해 fork 될 worker에게 전달하는 execArgv 값을 master의 process.execArgv 에다가
–debug-port=XXXX 이런 식으로 바꾸어서 실행 되도록 하는 등… 번거로운 작업을 했습니다.


BS의 경우에는 아예 모듈하나 만들어서 debug 모드에서는 cluster를 사용하지 않고 단일 프로세스로, debug 모드가 아닐 경우에는 cluster를 사용하는 멀티 프로세스로 동작하도록 했습니다.


그런데 v0.12.0 에서 이 부분이 변경이 되어 발표되었습니다.


[GitHub의 Node.js cluster.js 소스]를 보면


var workerEnv = util._extend({}, process.env);
var execArgv = cluster.settings.execArgv.slice();
var debugPort = process.debugPort + id;
var hasDebugArg = false;

workerEnv = util._extend(workerEnv, env);
workerEnv.NODE_UNIQUE_ID = ” + id;

for (var i = 0; i < execArgv.length; i++) {
  var match = execArgv[i].match(/^(–debug|–debug-brk)(=\d+)?$/);

  if (match) {
 execArgv[i] = match[1] + ‘=’ + debugPort;
 hasDebugArg = true;
  }
}

if (!hasDebugArg)
  execArgv = [‘–debug-port=’ + debugPort].concat(execArgv);


위와 같은 코드를 볼 수 있습니다.
worker 프로세스를 생성하는 함수 createWorkerProcess() 안에 있는데
내용은


master의 debug port + worker의 id 한 값을 debug port로 무조건 사용한다

입니다. 심지어는 debug 모드가 아닌 경우에도 –debug-port 옵션을 설정합니다!


이것 때문에 debug 모드를 검사하던 방법을 바꿔야 했습니다.


var isDebuggingMode = process[“execArgv”].some((argv) => {
  return /^(–debug|–debug-brk)(=\d+)?$/.test(argv);
});

그런데 여기서 드는 의문점…


TCP/IP 의 port 라는 것은 0 ~ 65535 일 수 밖에 없는데 (2바이트의 정수)…
cluster.fork()로 생성되는 worker의 id 는 무조건 증가만 되게 되어 있어서


cluster.fork = function(env) {
  cluster.setupMaster();
  var id = ++ids;
  var workerProcess = createWorkerProcess(id, env);
  var worker = new Worker({
    id: id,
    process: workerProcess
  });
  …

[Node.js cluster 문서의 cluster event “exit” 설명]에 나오는 아래 예제처럼 작성할 경우


cluster.on(‘exit’, function(worker, code, signal) {
  console.log(‘worker %d died (%s). restarting…’,
    worker.process.pid, signal || code);
  cluster.fork();
});

결국은 debug port가 65535가 넘어가는 사건이 발생하게 됩니다.


결론




  1. Node.js의 cluster 모듈 사용할 때에는 worker를 동적으로 계속 생성하지 않도록 한다.

  2. 동적으로 fork()할 일이 있는 어플리케이션은 cluster 모듈을 사용하지 말고 child_process 모듈을 사용한다.

  3. port 공유가 필요하고 동적으로 fork()를 해야 하는 어플리케이션은 C++로 직접 구현해서 붙인다
    (또는 잘 찾으면 이런 걸 한방에 해결하는 module이 있을지도)