前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# node部署

30 秒速记

  • 部署 = 环境可复现 + 进程有人管 + 发布能回滚,不是 git pull 完 node app.js
  • 版本锁死:.nvmrc / engines 固定 Node 版本,yarn.lock / package-lock.json 配 npm ci 装依赖
  • 进程交给 PM2 / systemd / 容器平台托管:崩溃自动拉起,开机自启,日志统一收
  • 配置和密钥走环境变量在运行时注入,不打进镜像也不进仓库
  • 应用自己要做三件事:/health 健康检查、收到 SIGTERM 优雅退出、启动失败返回非 0 退出码

Node 部署说白了要解决三个问题:线上跑的环境和本地一致、进程挂了有人拉起来、发布出问题能马上退回去。 环境一致靠锁版本,Node 版本写进 .nvmrc 或 Docker 基础镜像,依赖用 npm ci 严格按锁文件装。进程托管交给 PM2、systemd 或者 K8s,别用 nohup 凑合。应用这边我一般会补一个 /health 接口、处理 SIGTERM 做优雅退出,配置缺失时直接 process.exit(1),让发布脚本能发现失败并回滚,而不是带着坏配置继续跑。

理解「node部署」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 module 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

一次靠谱的 Node 服务发布,大致是下面这条线,每一步都能回答「失败了怎么办」:

  1. 构建阶段:在固定版本的镜像里 npm ci、跑测试、打包,产物只带运行要用的文件(dist、生产依赖),devDependencies 不进生产镜像。
  2. 启动阶段:从环境变量读配置,启动时就校验,缺了直接退出。
// config.js:启动时校验,缺什么一眼看出来
const required = ['DATABASE_URL', 'JWT_SECRET']
const missing = required.filter((k) => !process.env[k])
if (missing.length) {
  console.error('缺少环境变量:', missing.join(', '))
  process.exit(1) // 非 0 退出码,发布脚本 / PM2 / K8s 都能识别为失败
}
@前端进阶之旅: 代码已经复制到剪贴板
  1. 托管阶段:交给 PM2、systemd 或容器平台,负责崩溃重启、开机自启、日志收集。
  2. 切流阶段:新实例 /health 返回 200 之后再把流量切过去,旧实例收到 SIGTERM 后停止接新请求、处理完手头请求再退出。
  3. 回滚阶段:保留上一版镜像或上一版代码目录,健康检查不过就切回去,回滚要能一条命令搞定。

单机小项目 PM2 足够;多机或者已经用上容器的,直接用 Docker + 编排平台,PM2 在容器里的意义就不大了,因为重启和多副本平台都管了。

面试官追问

追问 1配置文件缺了一个数据库地址,服务照样启动成功了,有什么问题?
参考回答

它会在第一个请求进来时才炸,发布流程却已经判定成功、旧版本也下线了。启动阶段就校验必需配置,缺了直接 process.exit(1),让 PM2 / K8s / 发布脚本拿到非零退出码,自动停住发布。

追问 2本地 node app.js 能跑,服务器上一启动就报语法错误,先查什么?
参考回答

先看两边 node -v。最常见的是服务器 Node 版本太老,不认识可选链 ?.、顶层 await 这类语法。在 package.json 写 "engines": { "node": ">=18" },镜像也固定成同一个大版本。

追问 3为什么服务器上装依赖要用 npm ci 而不是 npm install?
参考回答

npm ci 严格按 package-lock.json 装,锁文件和 package.json 对不上会直接报错,而且会先删掉 node_modules。npm install 可能顺手升级小版本,今天和昨天装出来的东西不一样,线上问题就很难复现。

追问 4服务一直重启,日志里只有一行启动成功,怎么判断是谁杀的?
参考回答

先看托管方的记录:pm2 describe 里的重启次数和退出码,K8s 看 kubectl describe pod 里是不是 OOMKilled 或健康检查失败。退出码 137 一般是被 SIGKILL,多半是内存超限,应用日志里当然什么都没有。

追问 5日志写到容器里的 logs/app.log 有什么坏处?
参考回答

容器一重建日志就没了,多实例时还得挨个进容器翻。容器里直接写 stdout / stderr,交给 docker logs 或日志采集组件统一收;非要写文件也要挂卷加轮转。

# 一、forever

30 秒速记

  • forever 是最早一批 Node 进程守护工具:终端 / SSH 断开进程不死,崩溃了自动重启
  • 常用命令:forever start app.js / forever stop app.js / forever list,-w 监听文件变动重启
  • 和 nohup 的区别:nohup 只管断开终端不死,进程崩了就真没了
  • 现在基本不维护了,新项目选 PM2 或 systemd / 容器平台;它没有集群模式和日志聚合

forever 就是一个保活工具,让 Node 进程脱离终端在后台跑,挂了自动拉起来。 以前在服务器上直接 node app.js,SSH 一断进程就跟着退了,forever start app.js 解决的就是这个问题,外加崩溃重启。它的能力也就到这儿了,多进程、日志聚合、监控面板都没有,而且项目已经很久没怎么更新。现在我新项目不会再选它,单机用 PM2,有容器就交给平台。

forever则可以在cmd或ssh连接断开时,让项目一直运行,而且可以在项目崩溃时自动重启

  • 安装 npm install -g forever
  • forever的帮助手册 forever --help
  • 使用forever启动项目 forever start app.js
  • 使用forever停止项目 forever stop app.js
  • 列出所有通过forever管理的项目 forever list
  • 监视项目中的文件,当文件有变动时重启项目 forever -w start app.js

面试官追问

追问 1nohup node app.js & 不也能让进程在后台一直跑吗?
参考回答

能在后台跑,但进程一旦因为未捕获异常退出,就没人管了,第二天用户告诉你网站打不开。forever / PM2 多做的就是「监视进程,挂了重新拉起」这一步。

追问 2forever 显示服务一直在重启,用户请求总断,怎么查?
参考回答

先在前台直接 node app.js 跑一下,多半一启动就抛错,比如端口被占、配置缺失,forever 只是在机械地反复拉起。再看重启是不是和文件改动同步,开了 -w 又往项目目录写日志,就会自己触发自己。

追问 3生产环境能开 forever -w 吗?
参考回答

一般不开。线上代码靠发布流程更新,不需要监听文件;而且日志、上传目录如果在监听范围内,写一次文件就重启一次,请求会被莫名其妙地掐断。

追问 4一台机器上跑了好几个项目,入口都叫 app.js,forever stop app.js 会出什么事?
参考回答

很容易停错。按 forever list 里的序号或者启动时用 --uid 起个名字,再按名字停,比按文件名可靠得多。

追问 5老项目一直用 forever,要不要迁到 PM2?
参考回答

需要多实例、日志切割、内存超限重启的话就迁,成本不高,就是换个启动命令加一份 ecosystem.config.js。只是单进程保活、跑得好好的内部工具,没必要为换而换。

# 二、pm2

30 秒速记

  • PM2 = 进程守护 + 集群模式 + 日志 + 监控,单机部署 Node 的事实标准
  • 日常命令:pm2 start / list / logs / monit / restart / reload / delete
  • -i max(或 -i 0)按 CPU 核数开 cluster 进程;reload 逐个重启做到不停机,restart 是一起重启
  • 配置写进 ecosystem.config.js:watch / ignore_watch、max_memory_restart、env、日志路径
  • 坑:改了配置文件再 start 不会生效,要 delete 后重新 start,或者 reload ... --update-env

PM2 是 Node 的进程管理器,负责把应用跑起来、挂了拉起来、多核机器上开多个进程,再顺便把日志和监控管了。 一般我会把配置写进 ecosystem.config.js,pm2 start ecosystem.config.js 一把启动。线上发版用 pm2 reload,在 cluster 模式下它会一个个进程轮着重启,始终有进程在接请求;restart 是全部杀掉再起,会有一小段不可用。还有个常见坑,改了配置文件后直接 pm2 start 进程会沿用旧配置,要先 pm2 delete 再启动。

部署参考 http://blog.poetries.top/2018/11/18/react-ssr-next-deploy/

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
      • 一、forever
      • 二、pm2
      • 可运行示例:优雅关闭最小 HTTP 服务
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

node部署|Nodejs专题系列

# node部署

30 秒速记

  • 部署 = 环境可复现 + 进程有人管 + 发布能回滚,不是 git pull 完 node app.js
  • 版本锁死:.nvmrc / engines 固定 Node 版本,yarn.lock / package-lock.json 配 npm ci 装依赖
  • 进程交给 PM2 / systemd / 容器平台托管:崩溃自动拉起,开机自启,日志统一收
  • 配置和密钥走环境变量在运行时注入,不打进镜像也不进仓库
  • 应用自己要做三件事:/health 健康检查、收到 SIGTERM 优雅退出、启动失败返回非 0 退出码

Node 部署说白了要解决三个问题:线上跑的环境和本地一致、进程挂了有人拉起来、发布出问题能马上退回去。 环境一致靠锁版本,Node 版本写进 .nvmrc 或 Docker 基础镜像,依赖用 npm ci 严格按锁文件装。进程托管交给 PM2、systemd 或者 K8s,别用 nohup 凑合。应用这边我一般会补一个 /health 接口、处理 SIGTERM 做优雅退出,配置缺失时直接 process.exit(1),让发布脚本能发现失败并回滚,而不是带着坏配置继续跑。

理解「node部署」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 module 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

一次靠谱的 Node 服务发布,大致是下面这条线,每一步都能回答「失败了怎么办」:

  1. 构建阶段:在固定版本的镜像里 npm ci、跑测试、打包,产物只带运行要用的文件(dist、生产依赖),devDependencies 不进生产镜像。
  2. 启动阶段:从环境变量读配置,启动时就校验,缺了直接退出。
// config.js:启动时校验,缺什么一眼看出来
const required = ['DATABASE_URL', 'JWT_SECRET']
const missing = required.filter((k) => !process.env[k])
if (missing.length) {
  console.error('缺少环境变量:', missing.join(', '))
  process.exit(1) // 非 0 退出码,发布脚本 / PM2 / K8s 都能识别为失败
}
@前端进阶之旅: 代码已经复制到剪贴板
  1. 托管阶段:交给 PM2、systemd 或容器平台,负责崩溃重启、开机自启、日志收集。
  2. 切流阶段:新实例 /health 返回 200 之后再把流量切过去,旧实例收到 SIGTERM 后停止接新请求、处理完手头请求再退出。
  3. 回滚阶段:保留上一版镜像或上一版代码目录,健康检查不过就切回去,回滚要能一条命令搞定。

单机小项目 PM2 足够;多机或者已经用上容器的,直接用 Docker + 编排平台,PM2 在容器里的意义就不大了,因为重启和多副本平台都管了。

面试官追问

追问 1配置文件缺了一个数据库地址,服务照样启动成功了,有什么问题?
参考回答

它会在第一个请求进来时才炸,发布流程却已经判定成功、旧版本也下线了。启动阶段就校验必需配置,缺了直接 process.exit(1),让 PM2 / K8s / 发布脚本拿到非零退出码,自动停住发布。

追问 2本地 node app.js 能跑,服务器上一启动就报语法错误,先查什么?
参考回答

先看两边 node -v。最常见的是服务器 Node 版本太老,不认识可选链 ?.、顶层 await 这类语法。在 package.json 写 "engines": { "node": ">=18" },镜像也固定成同一个大版本。

追问 3为什么服务器上装依赖要用 npm ci 而不是 npm install?
参考回答

npm ci 严格按 package-lock.json 装,锁文件和 package.json 对不上会直接报错,而且会先删掉 node_modules。npm install 可能顺手升级小版本,今天和昨天装出来的东西不一样,线上问题就很难复现。

追问 4服务一直重启,日志里只有一行启动成功,怎么判断是谁杀的?
参考回答

先看托管方的记录:pm2 describe 里的重启次数和退出码,K8s 看 kubectl describe pod 里是不是 OOMKilled 或健康检查失败。退出码 137 一般是被 SIGKILL,多半是内存超限,应用日志里当然什么都没有。

追问 5日志写到容器里的 logs/app.log 有什么坏处?
参考回答

容器一重建日志就没了,多实例时还得挨个进容器翻。容器里直接写 stdout / stderr,交给 docker logs 或日志采集组件统一收;非要写文件也要挂卷加轮转。

# 一、forever

30 秒速记

  • forever 是最早一批 Node 进程守护工具:终端 / SSH 断开进程不死,崩溃了自动重启
  • 常用命令:forever start app.js / forever stop app.js / forever list,-w 监听文件变动重启
  • 和 nohup 的区别:nohup 只管断开终端不死,进程崩了就真没了
  • 现在基本不维护了,新项目选 PM2 或 systemd / 容器平台;它没有集群模式和日志聚合

forever 就是一个保活工具,让 Node 进程脱离终端在后台跑,挂了自动拉起来。 以前在服务器上直接 node app.js,SSH 一断进程就跟着退了,forever start app.js 解决的就是这个问题,外加崩溃重启。它的能力也就到这儿了,多进程、日志聚合、监控面板都没有,而且项目已经很久没怎么更新。现在我新项目不会再选它,单机用 PM2,有容器就交给平台。

forever则可以在cmd或ssh连接断开时,让项目一直运行,而且可以在项目崩溃时自动重启

  • 安装 npm install -g forever
  • forever的帮助手册 forever --help
  • 使用forever启动项目 forever start app.js
  • 使用forever停止项目 forever stop app.js
  • 列出所有通过forever管理的项目 forever list
  • 监视项目中的文件,当文件有变动时重启项目 forever -w start app.js

面试官追问

追问 1nohup node app.js & 不也能让进程在后台一直跑吗?
参考回答

能在后台跑,但进程一旦因为未捕获异常退出,就没人管了,第二天用户告诉你网站打不开。forever / PM2 多做的就是「监视进程,挂了重新拉起」这一步。

追问 2forever 显示服务一直在重启,用户请求总断,怎么查?
参考回答

先在前台直接 node app.js 跑一下,多半一启动就抛错,比如端口被占、配置缺失,forever 只是在机械地反复拉起。再看重启是不是和文件改动同步,开了 -w 又往项目目录写日志,就会自己触发自己。

追问 3生产环境能开 forever -w 吗?
参考回答

一般不开。线上代码靠发布流程更新,不需要监听文件;而且日志、上传目录如果在监听范围内,写一次文件就重启一次,请求会被莫名其妙地掐断。

追问 4一台机器上跑了好几个项目,入口都叫 app.js,forever stop app.js 会出什么事?
参考回答

很容易停错。按 forever list 里的序号或者启动时用 --uid 起个名字,再按名字停,比按文件名可靠得多。

追问 5老项目一直用 forever,要不要迁到 PM2?
参考回答

需要多实例、日志切割、内存超限重启的话就迁,成本不高,就是换个启动命令加一份 ecosystem.config.js。只是单进程保活、跑得好好的内部工具,没必要为换而换。

# 二、pm2

30 秒速记

  • PM2 = 进程守护 + 集群模式 + 日志 + 监控,单机部署 Node 的事实标准
  • 日常命令:pm2 start / list / logs / monit / restart / reload / delete
  • -i max(或 -i 0)按 CPU 核数开 cluster 进程;reload 逐个重启做到不停机,restart 是一起重启
  • 配置写进 ecosystem.config.js:watch / ignore_watch、max_memory_restart、env、日志路径
  • 坑:改了配置文件再 start 不会生效,要 delete 后重新 start,或者 reload ... --update-env

PM2 是 Node 的进程管理器,负责把应用跑起来、挂了拉起来、多核机器上开多个进程,再顺便把日志和监控管了。 一般我会把配置写进 ecosystem.config.js,pm2 start ecosystem.config.js 一把启动。线上发版用 pm2 reload,在 cluster 模式下它会一个个进程轮着重启,始终有进程在接请求;restart 是全部杀掉再起,会有一小段不可用。还有个常见坑,改了配置文件后直接 pm2 start 进程会沿用旧配置,要先 pm2 delete 再启动。

← 环境搭建基础应用 →

fe