You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
var child = require('child_process').fork('child.js');
var server = require('net').createServer();
server.on('connection', function (socket) {
socket.end('handled by parent\n');
});
server.listen(1337, function () {
child.send('server', server);
});
child.js
process.on('message', function (m, server) {
if (m === 'server') {
server.on('connection', function (socket) {
socket.end('handled by child\n');
});
}
})
var fork = require('child_process').fork;
var cpus = require('os').cpus();
var server = require('net').createServer();// tcp服务
server.listen(1337);
var workers = {};
var createWorker = function () {
var worker = fork(__dirname + '/worker.js');
// 接受子进程的信号,在错误子进程退出之前就启动新子进程,
worker.on('message',function (message) {
if(message.act == 'suicide'){
createWorker();
}
});
// 子进程exit退出
worker.on('exit', function () {
console.log('Worker ' + worker.pid + ' exited.');
delete workers[worker.pid];
});
// 发送句柄
worker.send('server', server);
workers[worker.pid] = worker;
console.log('Create worker. pid: ' + worker.pid);
};
// 启动对应的进程数
for (var i = 0; i < cpus.length; i++) {
createWorker();
}
process.on('exit', function () {
for (var pid in workers) {
workers[pid].kill();
}
});
worker.js
var http = require('http');
var server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('handled by child, pid is ' + process.pid + '\n');
lll
});
var worker;
process.on('message', function (m, tcp) {
if (m === 'server') {
worker = tcp;
worker.on('connection', function (socket) {
server.emit('connection', socket);
});
}
});
// 捕获异常错误
process.on('uncaughtException', function (err) {
// 录日志
logger.error(err);
// 发送自杀信号
process.send({act: 'suicide'});
// close保持当前请求清理完之后退出。不在接受新的请求。
worker.close(function () {
process.exit(1);
});
});
cluster(node原生模块)
cluster用以解决多多核CPU的利用率的问题。
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('exit', function (worker, code, signal) {
console.log('worker ' + worker.process.pid + ' died');
});
} else {
// In this case its a HTTP server
http.createServer(function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}).listen(8000);
}
玩转node process
事件驱动
为了处理高并发问题,事件驱动的服务器模式出现,node与nginx都是基于事件驱动实现的。
采用单线程避免了不必要的内存开销和上下文切换开销
如何充分利用CPU服务器?(child_process)
启动多进程即可。每个进程利用一个cpu,node提供了child_process模块,并且也提供了child_process.fork()函数供我们实现进程的复制
主进程不负责具体的业务处理,而是负责调度工作进程,工作进程负责具体的业务处理
worker.js
master.js
以上是通过fork多个进程,(port都是不一样的,后续通过进程之间句柄传递)只是为了充分将CPU资源利用起来,而不是解决并发问题,并发问题是node通过事件驱动的方式在进程上解决的
进程间的通信
子进程对象则由send()方法实现主进程向子进程发送数据,message事件实现收听子进程发来的数据。
parent.js
sub.js
父进程与子进程之间会出创建IPC通道,通过IPC通道,父子进程之间才能通过message和send传递消息;
进程间通信的原理
父进程在创建子进程之前,会创建IPC通道并监听它,然后才真正创建子进程,并通过环境变量(NODE_CHANNEL_FD)告诉子进程这个IPC通道的文件描述符(FD)。子进程在启动的过程中,根据文件描述符趣连接这个已经存在的IPC通道,从而完成父子进程之的连接
句柄传递(实现多个进程监听相同的port)
send方法除了能够通过IPC发送数据外,还能发送句柄
child.js
备注:直接将一个TCP服务发送给子进程。
如何保证进程的健壮性和稳定性?
worker.js
cluster(node原生模块)
cluster用以解决多多核CPU的利用率的问题。
事实上cluster模块就是child_process和net(提供tcp服务)模块的组合应用。
pm2
pm2是内建负载均衡,后台运行,0秒的重载。 PM2是完美的。
pm2的两种运行模式:
egg
egg是阿里提供的一种企业级的框架。egg不在依赖于pm2守护node进程,同时提供了各种约定,非常不错
在框架里,我们采用 graceful 和 egg-cluster 两个模块配合实现上面的逻辑。这套方案已在阿里巴巴和蚂蚁金服的生产环境广泛部署,且经受过『双11』大促的考验,所以是相对稳定和靠谱的。
备注
cluster原理
简述token
token是现在防止csrf的攻击比较流程的方案:
备注: 两者的方式之后token的种植的方式不一样。
redis一些使用场景
redis队列缓存是高并发必备法器,Redis运行在内存中但是可以持久化到磁盘,比起每次查询数据库要快很多
句柄详解
send()方法在将消息发送带IPC管道前,将消息组装成两个对象,一个参数是handle,一个是message
The text was updated successfully, but these errors were encountered: