Nodejs的主进程是单线程的,但它有多线程处理方案(更准备来说是多进程方案),即主进程开启不同的子进程,主进程接收所有请求,然后将分发给其它不同的nodejs子进程处理。
它一般有两种实现:
- 主进程监听一个端口,子进程不监听端口,通过主进程分发请求到子进程;
- 主进程和子进程分别监听不同端口,通过主进程分发请求到子进程。
cluster模式
Nodejs
的cluster模式
用的就是第一种实现,它使用一个主线程master
和多个子线程worker
,形成一个集群,通过主线程来向子线程分发请求。cluster 实现了对 child_process
的封装,通过 fork
方法创建子进程的方式实现了多进程模型。
cluster的使用
http
和cluster
、process
都是nodejs
的内置模块,不需要额外安装
- 创建一个http服务
// http是nodejs内置模块
const http = require('http')
const server = http.createServer((req, res) => {
res.write('hello http!')
res.end()
})
server.listen(3030, () => {
console.log('server is listening on http://localhost:3030')
})
// process是node的进程模块,可以从这个模块获取进程的信息,以及控制进程的
console.log(`worker ${process.pid} start`)
- 创建cluster
在下面程序中,会首先判断有没有主进程,如果没有,就创建进程,它会默认第一个进程为主进程
- 在源码中,是调用
cluster.fork()
方法时,会执行setupPrimary
方法创建主进程,它会使用initialized
标识是否为true
会判断是否为首次创建,如果是就创建主进程,否则就跳过 - 使用
createWorkerProcess
来创建子进程,这个方法实际是使用child_process
来创建子进程的
const cluster = require('cluster')
// 开启的子进程数
const workerNum = 3;
// 如果是主进程
if(cluster.isMaster) {
// 创建子进程
for(let i = 0; i < workerNum; i++) {
// 通过cluster.fork创建子进程
cluster.fork()
}
// 如果有子进程,就启动相关服务,这里会使用三个进程来执行http服务演示
}else {
require('./http-server')
}
image.png
实现过程大概是这样的: cluster
模块应用 child_process
来创建子进程,子进程通过复写掉 cluster._getServer
方法,从而在 server.listen
来保证只有主进程监听端口,主子进程通过 IPC
进行通信,其次主进程根据平台或者协议不同,应用两种不同模块(round_robin_handle.js
和shared_handle.js
)进行请求分发给子进程处理。
PM2
PM2是后台进程管理器,是多进程方案的一个成熟应用,可以帮助管理和保持应用程序在线。
基本使用
全局安装:npm install pm2@latest -g
它的使用也非常简单:
- 开启(http-server.js是要启动的程序):
pm2 start http-server.js
- 重启(程序):
restart app_name
- 重载(配置和程序):
reload app_name
- 停止:
pm2 stop app_name
- 删除:
pm2 delete app_name
- 监听模式:
pm2 start xx.js --watch
负载均衡:
PM2对nodejs应用,可以根据系统自动实现负载均衡:pm2 start http-server.js -i max
PM2配置
我们肯定不想每次启动时,都要手动输入一堆指令,所以我们可以将这些配置统一使用配置文件来管理,注意js文件名必须是 xxx.config.js
,我这里用ecosystem.config.js
:
apps
数组中,可以放置多个对象,对应多个文件执行不同的配置
// ecosystem.config.js
module.exports = {
apps : [{
name: "http-server", // 启动进程名
script: "./src/http-server.js", // 启动文件
instances: 4, // 启动进程数
exec_mode: 'cluster', // 多进程多实例
// 设置不同环境的环境配置
// 开发环境,对应--env 后的参数
env_development: {
NODE_ENV: "dev",
watch: true, // 开发环境使用 true,其他设置为 false
},
// 测试环境
env_testing: {
NODE_ENV: "test",
watch: false, // 开发环境使用 true,其他设置为 false
},
// 生产环境
env_production: {
NODE_ENV: "prod",
watch: false, // 开发环境使用 true,其他必须设置为 false
},
// 日志日期格式
log_date_format: 'YYYY-MM-DD HH:mm Z',
// 错误日志文件,必须设置在项目外的目录,这里为了测试
error_file: '~/Desktop/logs/err.log',
// 流水日志,包括 console.log 日志,必须设置在项目外的目录,这里为了测试
out_file: '~/Desktop/logs/info.log',
// 最大重启数据,当应用被认定连续n次不稳定重启起,再重启
max_restarts: 10,
},{
name: "express-test", // 启动进程名
script: "./src/express-test.js", // 启动文件
instances: 4, // 启动进程数
exec_mode: 'cluster', // 多进程多实例
}]
}
执行配置:pm2 start ecosystem.config.js --env dev
可以看到在启动后,桌面上生成了流水和错误日志:
日志
流水日志
参考:
Node Process模块 API:http://nodejs.cn/api/process.html
pm2官网: https://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/
网友评论