nodejs多进程
《深入浅出NodeJS》—— 朴灵 玩转进程篇的部分笔记
多进程架构
使用nodejs自带进程相关的模块复制进程。
1 | //master.js |
node mastar.js
程序依据当前机器上的CPU数量,复制出数量相当的node进程数。每个进程监听1000-2000的随机四个端口。
- 这种模式叫做主从模式。
- 这是典型的分布式架构中用于并行处理业务的模式,具有较好的可伸缩性和稳定性。
- 主进程负责调度或管理工作进程,不负责具体的业务处理,进程趋于稳定。
- 工作进程负责具体的业务处理,工作进程需要关注其稳定性。
创建子进程的方法
- spawn(): 启动一个子进程来执行命令。
- exec(): 启动一个子进程来执行命令,与spawn()不同的时其接口不同,他有一个回调函数获知子进程的状况。
- execFile(): 启动一个子进程来执行可执行文件。
- fork(): 与spawn()类似,不同在于它创建的node的子进程只需制定要执行的JS文件模块即可。
1 | var cp = require('child_process'); |
进程间通信
对于child_process模块,通过fork()或者其他API,创建子进程后,父进程与子进程之间建立IPC通道,通过IPC通道,父子进程之间通过message()和send()传递消息。
这是一种通过消息传递内容,而不是共享或直接操作相关资源的方法,比较轻量无依赖。
但是send()方法第二个参数已可以传递句柄(一种标示资源的引用),以实现更复杂的应用。
IPC
IPC(Inter-Process Communication)进程间通信。
实现进程间通信的方法有:命名管道,匿名管道,socket,信号量,共享内存,消息队列,Domain Socket等。
Nodejs中IPC由管道(PIPE)技术实现,具体细节由libuv提供,win下命名管道实现,* nix下Unix Domian Socket实现。
IPC创建步骤
- 父进程创建子进程前,会先创建IPC并监听。
- 创建子进程,并通过环境变量(NODE_CHANNEL_FD)告诉子进程这个IPC的文件描述符。
- 子进程启动过程中,通过文件描述符去连接IPC通道。
只有子进程时node进程时,子进程才会连接IPC通道,其他类型的进程无法实现此种方法的进程通信,除非其他进程也按照上述约定去连接IPC通道。
句柄传递
问题:
每一个进程启动时监听不同的端口,主进程要接收所有的网络请求,再将请求代理到不同端口的子进程上,这种方法虽然可以避免端口重复的问题,甚至可以适当的均衡负载,但是由于进程每收到一个连接,将会用掉一个文件描述符,这种代理模式,则会浪费掉多出一倍的文件描述符。而操作系统的文件描述符是有限的,这种法师影响了系统的扩展能力。
解决方法:
通过send方法的第二个参数,可以向进程发送句柄(即标示某资源的引用),使主进程收到socket请求后,将这个请求直接发送给工作进程,而不是重新与工作进程建立新的socket连接来发送数据。
当主进程将服务器句柄发给子进程后,关闭服务器的监听,则会发现所有的子进程都能监听到同一个端口了。
相关解释
发送的句柄不是真的对象,而是句柄文件描述符。
由于底层细节不被应用层感知,所以在子进程中,开发者会有种服务器就是从父进程直接传递过来的感觉。Node进程之间只传递消息,不传递对象,这种错觉时抽象封装的结果。Node目前只接受以下几种句柄类型:
- net.Socket: TCP套接字
- net.Server: TCP服务器
- net.Native: C++层面的TCP套接字或IPC管道
- dgram.Socket: UDP套接字
- dgram.Native: C++层面的UDP套接字
由于独立启动的进程直接并不知道文件描述符,所以监听相同端口会失败。但当使用send发送句柄从而还原出来的服务,它们的文件描述符时相同的,所以监听相同的端口不会引起异常。
多个应用监听相同的端口时,文件描述符同一时间只能被一个进程使用,
所以当有一个请求向服务端发送后,即使有多个应用监听同个端口,也只有一个进程为其服务,这些进程服务时 抢占式 的。
补补操作系统去→_→
…..