얼마전 LearnBoost에서 개발한 Cluster라는 Node.JS용 모듈을 알게되었습니다. 이 모듈은 노드 애플리케이션을 멀티-코어로 구동시켜 줍니다. 마스터, 워커로 간단하게 구성된 계층구조를 가지며 워커는 하나의 물리적인 코어를 가지게 되고 마스터만 죽이면 워커는 알아서 죽습니다. 또한 다양한 추가 기능을 제공하는 플러그인들이 있습니다. 특히, repl이라는 플러그인을 로드하면 telnet으로 접속할 수 있는 관리환경을 제공하게 되는데, 워커의 상황을 감시하고 즉시 죽이거나 스폰할 수있습니다. 기본적인 설치 및 사용방법은 다음과 같습니다.

# npm install cluster
# touch server.js
# vim server.js
var http = require('http');

var server = http.createServer(function(req, res){
  res.writeHead(200);
  res.end('Hello World');
});

// server start listening
if (module === require.main) server.listen(3000);
else module.exports  = server;

console.log('listen on port 3000');
# touch cluster.js
# vim cluster.js
var cluster = require('cluster');

cluster('./server')
  .use(cluster.repl('/var/run/cluster.sock'))
  .listen(3000);
# node cluster.js
listen on port 3000
listen on port 3000
listen on port 3000
listen on port 3000
listen on port 3000
listen on port 3000
listen on port 3000
listen on port 3000

# telnet /var/run/cluster.sock
cluster> help()

  Commands
  help(): Display help information
  spawn(n): Spawn one or more additional workers
  pids(): Output process ids
  kill(id, signal): Send signal or SIGTERM to the given worker
  shutdown(): Gracefully shutdown server
  stop(): Hard shutdown
  restart(): Gracefully restart all workers
  echo(msg): echo the given message
  stats(): Display server statistics

cluster> pids()
  master: 25930
  worker #0: 25933
  worker #1: 25934
  worker #2: 25935
  worker #3: 25936
  worker #4: 25937
  worker #5: 25938
  worker #6: 25939
  worker #7: 25940

제가 사용하는 가상서버의 코어는 8개입니다. 기본으로 하나의 코어에 하나의 워커를 배정하게 됩니다. 이제 포트 3000번으로 접속하는 서버 프로그램은 코어 래밸에서 클러스터링 된 것입니다. 참 쉽죠? 보다 자세한 사용방법은 api 문서를 숙지하세요.

epxpress 프레임웍으로 간단하게 만들어본 Firejune.I/O의 인덱스에 적용시키고 약 이틀정도 시간이 경과했습니다. 아주 잘돌아 가고 있어요. 주의해야 할 점은 서로다른 코어에서 작동하기 때문에 어떠한 변수를 참조할 수 없는 경우가 발생합니다. 그래서 이 변수를 워커들이 공유해야한다면 Redis와 같은 데이터스토어를 이용하여 해결해야합니다. MemoryStore를 기본으로 사용하는 Socket.IO역시 이러한 문제를 안고 있습니다. 접속이 성공적으로 이루어졌지만 상대방에게 메시지를 전송하지 못하는 상태인거죠. 그들은 사용할 Store를 옵션화하고 자체적으로 RedisStore를 제공하여 이 문제를 해결할 계획인듯 합니다.

var express= require('express')
  , sio = require('socket.io');

var app = express.createServer();
var io = sio.listen(app);
io.configure(function () {
  io.set('store', new sio.RedisStore);
});

if (module === require.main) app.listen(3000);
else module.exports  = app;

그러나 Socket.IO 최신버전(0.7.9)에서는 './lib/stores/redis.js'에서 'removeEvent'라는 속성이 없다는 오류가 발생합니다. 이 문제를 Daniel Shaw씨가 수정(그리고 이것)하여 GitHub에 풀(pull)된 상태이며 0.8 버전에서 적용될 것이라고 하네요. 이 소스를 반영하면 오류는 사라지지는데 뭔가(메모리가 누수되고 있다는;) 경고가 계속 나옵니다. 하지만 작동에는 이상이 없더군요. 송/수신 패킷이 상상을 초월하는 웹소켓에 적용하면 금상첨화 아니겠어요? 0.8이 나오기를 기다려 봐야겠습니다.

참고로, LampWebDevelopers.com에서도 자신들의 서비스에 Cluster 모듈을 적용하여 서버의 물리적 변화를 관측한 포스팅을 했습니다.

Comments

Got something to add? You can just leave a comment.

Your Reaction Time!

avatar

captcha