通常情况下, weroll应用程序的集群和Node.js官方的做法并没有区别, 例如:
/* ./main.js */
var App = require("weroll/App");
var app = new App();
var Setting = global.SETTING;
app.addTask(function(cb) {
var Model = require("weroll/model/Model");
Model.init(Setting.model, function(err) {
cb(err);
});
});
app.addTask(function(cb) {
//create and start a web application
var webApp = require("weroll/web/WebApp").start(Setting, function(webApp) {
/* setup Ecosystem */
var Ecosystem = require("weroll/eco/Ecosystem");
Ecosystem.init();
cb();
});
});
app.run();
/* ./cluster.js */
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
//setup weroll application
require("./server.js");
console.log(`Worker ${process.pid} started`);
}
或者使用pm2实现集群, 例如:
$ npm install -g pm2
$ pm2 start YOUR_APPLICATION_FOLDER/main.js -i MAX
集群并不会影响WebApp, APIServer和Ecosystem, 多个node进程将共享它们所使用的同一个端口. 具体请参考官方文档.
因此我们的主要问题是集群对Websocket长连接的影响. Realtime 集成了 socket.io-redis 使得weroll应用在集群环境下依然可以正常的使用Websocket.
在集群环境下, 每一个node进程中的Realtime将使用独立的端口, 而不是共享一个端口. 下面以官方的cluster为例:
/* ./main.js */
var App = require("weroll/App");
var app = new App();
var Setting = global.SETTING;
app.addTask(function(cb) {
var Realtime = require("weroll/web/Realtime");
var config = {
port: 3001,
allowGuest: true,
shakehand: false
};
Realtime.createServer(config).start();
cb();
});
app.run();
/* ./cluster.js */
const cluster = require('cluster');
const http = require('http');
const processNum = 4; //开启4核集群
if (cluster.isMaster) {
// Fork workers.
for (let i = 0; i < processNum; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
//setup weroll application
require("./main.js");
console.log(`Worker ${process.pid} started`);
}
执行结果如下:
Realtime的初始化参数中, 定义了port = 3001, 那么第一个进程的Realtime使用3001端口, 第二个进程的Realtime则使用3002端口, 第三个进程使用3003端口, 以此类推.
通常有两种方式供客户端使用长连接集群, 一是在连接前由服务端计算出一个负载较低的连接服务器的地址, 客户端再进行连接; 二是客户端使用域名进行websocket连接, 服务器通过Nginx等软件实现负载均衡, 也是socket.io官方推荐的一种做法.
Nginx负载均衡配置示例如下:
http {
...
upstream ws_nodes {
ip_hash;
server 127.0.0.1:6001;
server 127.0.0.1:6002;
server 127.0.0.1:6003;
server 127.0.0.1:6004;
}
...
server {
listen 3000;
server_name ws.yourdomain.com;
location / {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_pass http://ws_nodes;
}
}
}
相关文档: