关于Nodejs Cluster全局变量

最近破事比较多,博客更新收到了影响。

业务需要,学习了一下Nodejs里面的Process变量和Node cluster变量,收获不小。

这文章呢是针对cluster模块的,为什么要提process呢,因为这下面一部分代码需要用到process.

首先process是全局变量,是指nodejs主进程,所以呢上面的事件(message listening)都是相对于cluster中的master进程而言的,记住这个就好了,其他的不是本文重点。

cluster基于child_process模块实现,每个进程是对主进程的fork,之前我一直以为Cluster是多线程,其实它是多进程,既然是进程,他们都有独立的内存资源,全局变量不会共享(之前和一个朋友讨论过,怀疑使用cluster模块导致全局的SESSION变量被公用,高并发下产生了用户访问异常的问题,看来这个问题不是由cluster导致的),目的是解决NODEJS单线程模型对多核CPU利用率不高的问题。每个进程实际上还是单线程,可以通过linux taskset 命令把不同的进程绑到不同的CPU上来增加CPU的利用率。

废话不多说 上代码

test.js

var cluster = require('cluster'); 
var http = require('http'); 
 
if (cluster.isMaster) { 
  var numCPUs = require('os').cpus().length; 
  // 启动多个进程. 
  for (var i = 0; i < numCPUs; i++) { 
   //增加一个进程 
   	var wk = cluster.fork();
    
    let temp = function(msg){
      console.log('[worker] '+msg, this.id);
    }
    temp.id = wk.id;
    console.log(temp)
    wk.on('message', temp)
    wk.send('[master] ' + 'hi worker' + wk.id);
  } 
	process.on('listening', function (worker, address) {
		 console.log('[master] ' + 'listening: worker' + worker.id + ',pid:' + worker.process.pid + ', Address:' + address.address + ":" + address.port);
	});

	for (const id in cluster.workers) {
	    cluster.workers[id].on('message', messageHandler);
	  }
} else { 
	console.log('[worker] ' + "start worker ..." + cluster.worker.id);
	process.on('message', function(msg) {
      console.log('[worker] '+msg);
  });
	var server = http.createServer(function (req, res) {
    if(!share)
      var share = require('./share.js')
    share += 1;
     console.log('worker'+cluster.worker.id);
    process.send('test'+share)
	  	res.end('yes');
	});

	server.listen(8000, function () {
	 	console.log('Application worker started ...', process.pid);
	});
} 
share.js

if(!number){
	console.log('create number')
	var number = 1;
}

module.exports = number;

上面的代码根据CPU数量生成了N个进程,每个进程监听他们的message事件,然后在子进程中开启HTTP Server,收到request后由主进程向子进程发送消息,打出当前进程的Id(我在这里在每个MESSAGE回调函数上藏了一个属性,就是每个子进程的ID,然后 在回调函数中用this.id就可以打出当前进程的ID)

然后在share.js定义了一个全局变量,这是用来验证各个进程之间全局变量是否会共享。
按照nodejs官方文档,http请求默认的负载均衡方式为轮询,但是实际测试中发现请求有很大概率会打在同一个进程上(输出的进程ID相同),不论在Winodws下还是在LINUX下我都访问了很多次才访问到另外一个进程,后面专门研究下为什么会发生这种情况。
Windows下运行代码后 访问多次localhost:8000的截图
最后一个数字就是进程id test后面的2则是我们定义的全局变量number 可以看见不同的进程间全局变量的值打出来是一样的,而没有累加上去,说明它们之间是不同的变量。
这次运气好,访问了7次就访问到了另外一个进程上,上次截图我足足访问了几十次
这就验证了全局变量不共享的问题,上面代码也大致揭示了父子进程如何通过message事件来进行通信。之所以要验证这个问题,则是因为之前在业务上碰到一个奇怪的问题,场景如下:
我们的业务系统使用了cluster模块,同时使用了一个全局变量session,在高并发下,发现A用户的Session数据被写到了B用户的数据库记录中,怀疑是cluster模块下全局变量数据共享的问题,通过这个测试排除了这个问题。不过通过以上代码,可以看出require引进的变量,对于每个进程是唯一全局的(create number针对每个进程只出现了一次)
所以我现在的怀疑是,在取数据时,由于高并发连接被抛弃,所以存入了上一次保留的全局变量。
但是这个抛弃的连接可能性比较多有
1.http请求
2.MySQL请求
3.redis请求 
三个都是socket请求,nodejs采用net模块来进行socket连接,三者都是在net模块的基础上封装的,后面还要再做一下测试。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值