在如今机器的CPU都是多核的背景下,节点的单线程设计已经没法更充分的“压”榨机器性能了,所以从v0.8开始,节点新增了一个内置模块——“集群”,故名思议,它可以通过一个父进程管理一坨子进程的方式来实现集群的功能。
学习集群之前,需要了解过程相关的知识,如果不了解的话建议先阅读过程模块,child_process模块。
集群借助child_process模块的fork()方法来创建子进程,通过叉方式创建的子进程与父进程之间建立了IPC通道,支持双向通信。
集群模块最早出现在节点。js v0.8版本中
节点。js是单线程的,那么如果希望利用服务器的多核的资源的话,就应该多创建几个进程,由多个进程共同提供服务。如果直接采用下列方式启动多个服务的话,会提示端口占用。
const http=要求(“http”); 赫特普。res createServer(点播)=比;{ res.writeHead (200); res.end (“hello world \ n”); }).listen (8000);//启动第一个服务节点索引。js和//启动第二个服务节点索引。js和 把呃;//未处理的“错误”事件 ^ 错误:听EADDRINUSE::: 8000 在服务器上。setupListenHandle [_listen2) (net.js 1330:14): listenInCluster (net.js 1378:12): 在服务器上。听(net.js 1465:7): 在对象灵活;anonymous>(/用户/洗剂/工作/学习/node-basic/集群/simple.js: 25:4) 在模块。_compile(内部/模块/cj/loader.js: 702:30) 在Object.Module._extensions . .js(内部/模块/cj/loader.js: 713:10) 在模块。负载(内部/模块/cj/loader.js: 612:32) 在tryModuleLoad(内部/模块/cj/loader.js: 551:12) 在Function.Module。_load(内部/模块/cj/loader.js: 543:3) 在Function.Module.runMain(内部/模块/cj/loader.js: 744:10)
如果改用集群的话就没有问题
const集群=要求(“集群”); const http=要求(“http”); const numCPUs=要求(os) .cpus . length (); 如果(cluster.isMaster) { 控制台。日志(“${大师的过程。pid}运行”);//叉工人。 (让我=0;我& lt;numCPUs;我+ +){ cluster.fork (); } 集群。(“退出”(工人、代码、信号)=比;{ 控制台。日志($ {worker.process的工人。pid}去世的); }); 其他}{//员工可以分享任何的TCP连接//在这种情况下,它是一个HTTP服务器 赫特普。res createServer(点播)=比;{ res.writeHead (200); res.end (“hello world \ n”); }).listen (8000); 控制台。日志(“工人${过程。pid}开始'); }//节点索引。js执行完启动了一个主进程和8个子进程(子进程数与cpu核数相一致) 主11851年运行 11852年工人 11854年工人 11853年工人 11855年工人 11857年工人 11858年工人 11856年工人 工人11859年开始
集群创建的进程分两种,父进程和子进程,父进程只有一个,子进程有多个(一般根据cpu核数创建)
-
<李>父进程负责监听端口接受请求,然后分发请求。李>
<李>子进程负责请求的处理。李>
有三个问题需要回答:
-
<李>子进程为何调用听不会进行端口绑定李>
<李>父进程何时创建的TCP服务器李>
<李>父进程是如何完成分发的李>
净。js源码中的听方法通过listenInCluster方法来区分是父进程还是子进程,不同进程的差异在listenInCluster方法中体现
函数listenInCluster(服务器地址、端口、addressType积压,fd, excluseive) { 如果集群。isMaster | |独家){ 服务器。_listen2(地址、端口、addressType积压,fd); 返回; } const serverQuery={地址:地址……}; 集群。_getServer(服务器、serverQuery listenOnMasterHandle); 函数listenOnMasterHandle(呃,处理){ 服务器。_handle=处理; 服务器。_listen2(地址、端口、addressType积压,fd); } }
上面是精简过的代码,当子进程调用听方法时,会先执行_getServer,然后通过回调的形式指定服务器。_handle的值,之后再调用_listen2方法。
集群。_getServer=函数(obj、期权、cb) { … const消息=util._extend ({ 行为:“queryServer”, 指数:索引(indexesKey), 数据:零 },选项); 消息。地址=地址; (发送消息(回复、处理)=比;{ 如果(处理) 共享(回复、处理、indexesKey cb);//共享监听套接字。 其他的 rr(回复,indexesKey cb);//循环。 }); …node . js中集群的模块深入解读