çŸåšãNode.js + Express + Socket.IO ã§ã¢ããªã±ãŒã·ã§ã³ãäœæããŠããã®ã§ããã
ããã¡ãœããã§æéã®ãããåŠçãå
·äœçã«ã¯ãä»ã®ãµã€ãã®Web APIãã«ãŒãã§å©ãåŠçãããŸãã
ãã®ããããã®ã¡ãœãããçµãããªããšãå¥ã®ãªã¯ãšã¹ããåãä»ããŠããåŠçãå§ãŸããªãã®ã§ã
ClusteråãããŸããã
éåžžã®ã·ã³ã°ã«ã¹ã¬ããã§ã®èµ·åã®å Žåã¯ããŸãåäœããã®ã§ããã
ClusteråããããšãããSocket.IOã®socket.onã fire ãããªããªãã
ããããExpressã䜿ã£ãå Žåã®Clusteråãããããã®ãã
Clusteråããå Žåã®Socket.IOã®æžãæ¹ãééã£ãŠããã®ã
ããããããã®ç¹ã«é¢ããŠæããé¡ããããšæã£ãŠã¡ãŒã«ããŸããã
å ·äœçã«ã¯
cluster.js
----------------------------------------------
var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('death', function(worker) {
console.log('worker ' + worker.pid + ' died');
});
} else {
app = require('./app');
}
--------------------------------------------------
Experss ã®app.jsã®Socket.IOéšå
-----------------------------------------------
var io = require('socket.io');
io = io.listen(app);
io.sockets.on('connection', function (socket) {
console.log('connected --- server');
ãã socket.on('send_ex_id', function(data) {
^^^^^^^^^^^^^ ãããèµ·åããªã
console.log('---------experiment_id---------------',
data.experiment_id);
// other to do
});
console.log("----------io.sockets.on", new Date());
});
-----------------------------------------------
ãã®ãããªåœ¢ã«ãªã£ãŠããŸãã
Node V0.6.4
Express 2.5.2
Socket.IO 0.8.7
ããã§ã¯ããããããé¡ãããŸãã
> ããã¡ãœããã§æéã®ãããåŠçãå
·äœçã«ã¯ãä»ã®ãµã€ãã®Web APIãã«ãŒãã§å©ãåŠçãããŸãã
> ãã®ããããã®ã¡ãœãããçµãããªããšãå¥ã®ãªã¯ãšã¹ããåãä»ããŠããåŠçãå§ãŸããªãã®ã§ã
æ¬é¡ã§ã¯ãªãã®ãããããŸãããïŒãããæ ¹æ¬çã«ééã£ãŠãã®ã§ã¯ïŒ
ãšãããïŒfs ã¢ãžã¥ãŒã«ãªã ïœSync() ãããããã© http/net ã§
ãããã¯ããã®ã¯è³é£ã®æ¥ã®ãããªæ°ãïŒïŒïŒ
Socket.IO ã Express ã Node v0.6 ã® cluster ããµããŒã
ããŠãããã©ããã¯ä»ã®äººããããã§ããŒïŒ
--
{
name: "Koichi Kobayashi",
mail: "koi...@improvement.jp",
blog: "http://d.hatena.ne.jp/koichik/",
twitter: "@koichik"
}
æ¬é¡ã§ã¯ãªãã®ãããããŸãããïŒãããæ ¹æ¬çã«ééã£ãŠãã®ã§ã¯ïŒ
ãšãããïŒfs ã¢ãžã¥ãŒã«ãªã ïœSync() ãããããã© http/net ã§
ãããã¯ããã®ã¯è³é£ã®æ¥ã®ãããªæ°ãïŒïŒïŒÂ
> ãã ãDBããååŸããã¬ã³ãŒãæ°ã1000 ~ 10000ã«å¯ŸããŠhttpãªã¯ãšã¹ããçºè¡ããã®ã§ã
(ç¥)
> ããæžãæ¹ãŸããã§ããããïŒ
http.get() ãšããããã倧éã®ããŒã¿ãäžæ°ã«åŠçããã®ã
ãŸããã®ã§ã¯ãªãã§ããããã
process.nextTick() ãæããªããããããã£ãŠããããããŒå¶åŸ¡
ã¢ãžã¥ãŒã«ã䜿ããªãããæ¹ãããã§ãããã
Result.find({æ¡ä»¶}, function(results) {
var i = 0, len = results.length;
function processRow() {
for (var j = 0; i < len && j < 10; ++i, ++j) { // 10ä»¶ãã€åŠç
http.get(...);
}
if (i < len) {
process.nextTick(processRow);
}
}
processRow();
}
Date: Fri, 16 Dec 2011 18:37:37 +0900
From: Tsutomu Watanabe <watan...@gmail.com>
Subject: Re: [nodejs_jp:492] ClusterãšSocket.IO ã«ã€ããŠ
--
http.get() ãšããããã倧éã®ããŒã¿ãäžæ°ã«åŠçããã®ã
ãŸããã®ã§ã¯ãªãã§ããããã
process.nextTick() ãæããªããããããã£ãŠããããããŒå¶åŸ¡
ã¢ãžã¥ãŒã«ã䜿ããªãããæ¹ãããã§ãããã
> çµå±ã¯ããã®ãªã¯ãšã¹ãïŒäŸãã°http://localhost/mergeã®ãããªURLïŒã«å¯ŸããåŠçãã
> ã¯æãããªãã®ã§ãã€ãŸãã¡ã¢ãªã¹ã¿ãã¯äžããé€ãããªãéãããã®ãªã¯ãšã¹ãã«å¯Ÿãã
> åŠçã¯ãããã¯ãããã®ã§ã¯ãªãã§ããããïŒ
> 1ã€ã®ãªã¯ãšã¹ãã®äžã®åŠçã§ã¯ããããŒå¶åŸ¡ãªãããã³ããããã³ã°IOã§åã®åŠçã®çµäºã
> åŸ
ããã«ãåŠçãé²ãã§ãããŸããã
ã¡ãã£ãšæå³ãåãããŸãããïŒïŒïŒ
äžã€ã®ãªã¯ãšã¹ãã«å¯ŸããåŠç (http.get() ãåŒã³åºãåŠç) ã
仮㫠1 ããªç§ã ã£ãå ŽåïŒ10000 ä»¶äžæ°ã«è¡ããš 10 ç§ãããïŒ
ãã®éã¯ã€ãã³ãã«ãŒãã«æ»ããªãã®ã§ä»ã® I/O ããããã¯
ããããšã«ãªããŸããïŒ10 ä»¶ããšã«ã€ãã³ãã«ãŒãã«æ»ãã°
10 ããªç§ããšã«ä»ã® I/O ãåŠçã§ããŸãããïŒ
ããããããšãå¯èœãªãããŒå¶åŸ¡ã¢ãžã¥ãŒã«ããããŸãïŒ
Async.js (fjacobs/async.js) ãšãïŒ
# æè¿ JS ã¢ãã«ã¬ã§ç޹ä»ããã Async (caolan/async) ãšã¯
# 䌌ãååã®å¥ç©ïŒ
https://github.com/fjakobs/async.js
Result.find({æ¡ä»¶}, function(results) {
async.list(results)
.each(function(row) {
... // http.get() ãªã© 1 ä»¶ããšã®åŠç
})
.delay(0, 10) // 10 ä»¶ããšã«ã€ãã³ãã«ãŒãã«æ»ã
.end();
}
ã¿ãããªïŒ
> ä»ãmanualãèªã¿ã€ã€ãchild_processãããã»ã¹ã®UNIXã®forkã¿ãããªæããªã®ã§ã
> Node.jsã£ãœããªãã§ããããã©ã€ããŠã¿ãŸãã
child_process.fork() ã¯å®éã¯ãã ã® fork() ã§ã¯ãªãïŒ
fork()+exec() ãªã®ã§æ³šæïŒ
ãã¶ãïŒããããã©ã€ããå¿
èŠã¯ãªãã¯ãã§ããïŒ
ãããããïŒå°ããªåäœã§ã€ãã³ãã«ãŒãã«æ»ãããã«
ããæ¹ãéèŠã ãšæããŸããïŒ
ã¯ã©ã€ã¢ã³ããµã€ã (ãã©ãŠã¶) ã§ã setTimeout() ã
䜿ããªã©ããŠåŠçãå°ããåå²ããã®ãšåãã§ãïŒ
ã©ãã http.get() ã¯åããã¹ãã«å¯ŸããŠã¯ (ããã©ã«ãã§ã¯)
5 æ¥ç¶ããåæã«å®è¡ããªãã®ã§ïŒãã以äžäžæ°ã«åŒã³åºããŠã
广ã¯ãããŸããïŒ
æ ¹æ¬çãªåé¡ã®è§£æ±ºã«åãããïŒCluster ã詊ããã
child_process.fork() ã«ãã©ã€ãããšããã®ã¯çµå±ã¯
é åãã«ãªãããããªãããšæããŸãïŒ
> çµè«ããèšããšãprocessTickã䜿ã£ãŠããåãããã«
> ïŒã€ã®ãªã¯ãšã¹ããããŒã¿ãè£ããŠããéã¯ãä»ã®ãªã¯ãšã¹ãã¯
> åŸ
ããããŸããã
nextTick() ã®äœ¿ãæ¹ãæªãã®ã§ã¯ïŒ
ç¹°ãè¿ããŸããïŒãïŒã€ã®ãªã¯ãšã¹ããããŒã¿ãè£ããŠããéãã®
ãéäžãã§çްããã€ãã³ãã«ãŒãã«æ»ãã°ãããªããšã«ã¯ãªããŸããïŒ
> httpãçºè¡ããå Žæãšãres.endã®å Žæã§console.logã§ç¢ºèªããŠã¿ãŸãããã
> ã«ãŒãã§httpãçºè¡ããŠããéã«ããres.endãæ€ç¥ããããšãres.endã®å®è¡ãããŠããŸãã
ãããªã¯ãã¯ãããŸããïŒ
res.end() ã¯ã€ãã³ãã«ãŒãã«æ»ã£ãŠããåŒã³åºãããŸãïŒ
var http = require('http');
http.createServer(function(req, res) {
res.writeHead(200);
res.end();
}).listen(3000, function() {
processRequest('Foo');
});
function processRequest(name) {
for (var i = 0; i < 10; ++i) {
(function(i) {
http.get({port: 3000}, function(res) {
res.on('end', function() {
console.log(name, i, 'response end');
});
});
console.log(name, i, 'request end');
})(i);
}
console.log('=====', name, 'processRequest end =====');
}
å®è¡çµæ (Ctrl-C ã§çµäº)
Foo 0 request end
Foo 1 request end
Foo 2 request end
Foo 3 request end
Foo 4 request end
Foo 5 request end
Foo 6 request end
Foo 7 request end
Foo 8 request end
Foo 9 request end
===== Foo processRequest end =====
Foo 0 response end
Foo 1 response end
Foo 2 response end
Foo 3 response end
Foo 4 response end
Foo 5 response end
Foo 6 response end
Foo 7 response end
Foo 8 response end
Foo 9 response end
ãã®ããã«ïŒres.end() 㯠http.get() ãç¹°ãè¿ãåŒã³åºããŠãã
processRequest() ã®ã«ãŒããçµäºãããŸã§ïŒæ±ºããŠåŒã³åºãããŸããïŒ
ç¹°ãè¿ããã©ãã ã倧ããããŠãåæ§ã§ãïŒ
ãã®äŸã¯ãµãŒããåãããã»ã¹ã§å®è¡ããŠããã®ã§ïŒ
ã«ãŒãäžã«ã¬ã¹ãã³ã¹ãè¿ã£ãŠããŠããããã§ã¯ãããŸãããïŒ
å¥ããã»ã¹ã«ããŠãçµæã¯åãã§ãïŒ
> å°æãããèšã£ãŠãã®ã¯ãã«ãŒãã现åãã«ããŠããã®éäžã§ã
> ãã®ã«ãŒãã®äžã«ä»ããã®ãªã¯ãšã¹ãã®ã«ãŒãåŠçãèµ°ãããšããããšã§ããããïŒ
ããã§ãïŒ
> ããããããšã¯å¯èœãªãã§ããããïŒã
ã€ãã³ãã«ãŒãã«æ»ãã°å¯èœã§ãïŒ
> ãã®å Žåã®å€æ°ã®å€ãªã©ã¯ã©ããªãã®ã§ããããïŒ
JavaScript ãªã®ã§ã¯ããŒãžã£ãŒãå€çšããããšã«ãªããŸãïŒ
å
ã®äŸã®
}).listen(3000, function() {
processRequest('Foo');
});
ã
}).listen(3000, function() {
processRequest('Foo');
processRequest('Bar');
});
ãšå€æŽãããšïŒå®è¡çµæã¯æ¬¡ã®ããã«ãªããŸãïŒ
Foo 0 request end
Foo 1 request end
Foo 2 request end
Foo 3 request end
Foo 4 request end
Foo 5 request end
Foo 6 request end
Foo 7 request end
Foo 8 request end
Foo 9 request end
===== Foo processRequest end =====
Bar 0 request end
Bar 1 request end
Bar 2 request end
Bar 3 request end
Bar 4 request end
Bar 5 request end
Bar 6 request end
Bar 7 request end
Bar 8 request end
Bar 9 request end
===== Bar processRequest end =====
Foo 0 response end
Foo 1 response end
Foo 2 response end
Foo 3 response end
Foo 4 response end
Foo 5 response end
Foo 6 response end
Foo 7 response end
Foo 8 response end
Foo 9 response end
Bar 0 response end
Bar 1 response end
Bar 2 response end
Bar 3 response end
Bar 4 response end
Bar 5 response end
Bar 6 response end
Bar 7 response end
Bar 8 response end
Bar 9 response end
Foo (ãããäžã€ã®ãªã¯ãšã¹ãã ãšèããŠãã ãã) ãåŠç
ããŠããéïŒBar (ããã¯å¥ã®ãªã¯ãšã¹ã) ã¯åŠçãããŸããïŒ
ãããä»åã®åé¡ã§ãïŒ
ããã§ processRow() ãæ¬¡ã®ããã«ããŸãïŒ
function processRequest(name) {
var i = 0, len = 10;
(function processRows() {
for (var j = 0; i < len && j < 3; ++i, ++j) { // 3ä»¶ãã€åŠç
(function(i) {
http.get({port: 3000}, function(res) {
res.on('end', function() {
console.log(name, i, 'response end');
});
});
console.log(name, i, 'request end');
})(i);
}
if (i < len) {
process.nextTick(processRows);
}
})();
console.log('=====', name, 'processRequest end =====');
}
çµæã¯æ¬¡ã®ããã«ãªããŸãïŒ
Foo 0 request end
Foo 1 request end
Foo 2 request end
===== Foo processRequest end =====
Bar 0 request end
Bar 1 request end
Bar 2 request end
===== Bar processRequest end =====
Foo 3 request end
Foo 4 request end
Foo 5 request end
Bar 3 request end
Bar 4 request end
Bar 5 request end
Foo 6 request end
Foo 7 request end
Foo 8 request end
Bar 6 request end
Bar 7 request end
Bar 8 request end
Foo 9 request end
Bar 9 request end
Foo 0 response end
Foo 1 response end
Foo 2 response end
Bar 0 response end
Bar 1 response end
Bar 2 response end
Foo 3 response end
Foo 4 response end
Foo 5 response end
Bar 3 response end
Bar 4 response end
Bar 5 response end
Foo 6 response end
Foo 7 response end
Foo 8 response end
Bar 6 response end
Bar 7 response end
Bar 8 response end
Foo 9 response end
Bar 9 response end
Foo ã®åŠçã®åéã« Bar ã®åŠçãæãŸããŸããïŒ
Fooã»Bar ãããã 10 ä»¶ãã€ã ãšïŒå
šãŠã® GET ãªã¯ãšã¹ãã
å®äºããŠããã¬ã¹ãã³ã¹ãåä¿¡ããŸããïŒlen = 100 ãšããã°
GET ãªã¯ãšã¹ããå
šãŠå®äºããåã«ã¬ã¹ãã³ã¹ã®åä¿¡ã
æãŸã£ãŠããŸãïŒ
ããããïŒNode ã«éããã€ãã³ãé§åã®ããã°ã©ãã³ã°ã«
æ
£ããŠããªãã®ã§ã¯ãªãããšæããŸãïŒ
ã²ãšãŸãäžèšã®ãµã³ãã«ãã©ã®ãããªåããããã®ãïŒ
ã€ãã³ãã«ãŒããšã©ã®ããã«å調åäœãã¹ããªã®ãïŒ
ãã£ããèããŠã¿ãŠã¯ïŒ