用cluster的master可以共享多个worker的全局数据吗? - CNode技术社区

用cluster的master可以共享多个worker的全局数据吗?
发布于 9 年前 作者 yakczh 4479 次浏览 来自 问答

比如数据保存在一个全局变量 var message里 这样多个woker和 master都同时读写这个数据会不会出错呢? app.js

var cluster = require('cluster');
var io = require('socket.io')();
var numCPUs = require('os').cpus().length;
console.log(' numCPUs is ',numCPUs);
var connections=0;
if (cluster.isMaster) {
 console.log("master start...");
 // Fork workers.
 for (var i = 0; i < numCPUs; i++) {
 cluster.fork();
 }
 cluster.on('listening',function(worker,address){
 console.log('[Master ]listening: worker ' + worker.process.pid +', Address: '+address.address+":"+address.port);
 });
 cluster.on('exit', function(worker, code, signal) {
 console.log('[Master] worker exit ' + worker.process.pid + ' died');
 });
} else if (cluster.isWorker) {
 io.on('connection', function(socket) {
 console.log('this is process',process.pid);
 connections++;
 console.log("client ++",connections);
 socket.on('disconnect', function() {
 connections--;
 console.log("client --",connections);
 });
 socket.on('message',function (msg) {
 	console.log(msg);
 	 
 });
 });
io.listen(9000);
}

test.html

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>
		
	</title>
	<script src="/js/socket.io.js"></script>
</head>
<body>
	
<script type="text/javascript">
var socket = io.connect('ws://localhost:9000',{'reconnection':true});
socket.on('message', function(msg){
 console.log(msg);
});
 socket.emit('message',{foo:11,bar:22});
 
</script>
</body>
</html>

这样启动app.js ,用第一个浏览器刷页面,能看到 控制台显示 client ++ 但是第二个浏览器刷页面,没有反应

5 回复

最简单的办法是使用Redis。所有的worker都 向 Redis 里 写与读 全局数据。Redis也支持事务。我公司的WEB集群目前就是这么做的。什么session与application级的数据都在Redis里。 在Github里,nodejs的Redis Client库很多。如果再配合上async/await,代码就会更漂亮了。

我之前遇到过类似的问题。我的推测是:你的第二个浏览器的web socket连接并没有被Socket.io成功地创建。根据Socket.IO的文档,在集群工作模式下,Socket.IO创建连接要求"黏性会话"。要不然,Socket.IO,在集群模式下,创建web socket连接有概率性的失败。为此,Socket.IO的作者还实现过一个"黏性会话"的模块在github上:https://github.com/wzrdtales/socket-io-sticky-session 除了TCP握手之外,Socket.IO为保证对IE 10以下浏览器的向下兼容性,Socket.IO自己也有一个握手操作(基于若干个HTTP请求)。虽然这个功能很强大,但是,也给我们带来了额外的限制。 我建议:你把这个黏性会话的功能先加上,再试。

@stuartZhang 继续测试了一下, 这个负载均衡只有大量请求下才会显示 一两个单个的请求始终是一个Worker来完成

测试代码

const cluster = require('cluster');
var totalReqs = 0;
if (cluster.isMaster) {
	const numCPUs = require('os').cpus().length;
	console.log(numCPUs);
	var broadcast = function() {
		Object.keys(cluster.workers).forEach(function(i) {
		//	console.log(cluster.workers[i].process.pid + ":" + totalReqs);
			cluster.workers[i].send({total: totalReqs});
		});
	}
for (var i = 0; i < numCPUs; i++) {
		var worker = cluster.fork();
		worker.on('message', function(msg) {
			totalReqs++;
			broadcast();
		//		console.log(msg+ " master total is :"+totalReqs);	
		});
	}
} else {
	console.log(process.pid);
	const http = require('http');
	var localReq = 0;
	http.createServer((req, res) => {
		process.send(" worker " + process.pid + " local is " + localReq + " sum is " + totalReqs);
		res.writeHead(200);
		localReq++;
		//console.log("localreq is "+localReq+" sum is "+totalReqs);
		res.end("local is " + localReq + " total is " + totalReqs);
	}).listen(9000);
	process.on('message', function(msg) {
	 	//	console.log(msg.total);
	 		totalReqs=msg.total;
 });
}

ab -n 1000 -c 100 http://localhost:8000/
但是这样只有最后一个worker 会更新 totalReqs 其他的都显示是0 不知道是哪里的代码写错了

@stuartZhang 这个黏性会话是不是指 socket从连接到断开的整个过程中 就绑定某一个cpu核心 ?

@yakczh 这里的黏性会话指的是:同一个web client始终发请求给同一个web server实例(或 服务进程)。默认配置是:负载均衡器(也就是 你例子中的主进程)"随机转发"或"依次转发"请求给forked worker服务进程。这个和cpu没有关系。

回到顶部

AltStyle によって変換されたページ (->オリジナル) /