PM2部署后端服务,为什么偶尔会出现连接断开且日志没报错?
用PM2部署了一个Express服务,最近频繁出现客户端连接突然断开的情况,但PM2日志里完全没有报错。我试过用pm2 restart和检查配置文件,断开问题还是偶尔出现。服务是用cluster模式启动的,代码里也没有明显异常捕获遗漏,这是什么情况?
PM2启动命令是这样的:
pm2 start app.js -i max --name "api-server" --no-daemon
Node.js用了process.on('uncaughtException')和unhandledRejection,但日志里都没记录到异常…
同时换用
pm2 start app.js -i max --name "api-server" --no-daemon --trace开启追踪模式,看看有没有隐藏异常。第一个是负载均衡导致的连接中断。PM2在cluster模式下默认用round-robin调度,如果某个worker进程挂了或者重启,当前连在这个worker上的请求就会直接断开,而且Node层面上未必能捕获到异常,因为连接是操作系统层面被重置的。你可以试试把启动命令改成
pm2 start app.js -i max --name "api-server" --no-daemon --execution-mode cluster明确指定模式,虽然看着差不多但有时候版本差异会导致行为不同。第二个重点查的是系统资源限制。调试看看是不是文件描述符被打满了。你在服务器上运行
ulimit -n看看上限,再用lsof -p $(pgrep node) | wc -l查实际占用。如果接近上限,连接就会无声断掉,PM2日志也不会记录这种系统级问题。解决办法是在PM2配置里加环境变量限制,或者改系统配置。第三个可能性是心跳或超时设置不合理。Express本身不会主动维持长连接,如果你前面还有Nginx、ELB之类的代理,它们一般有60秒到300秒不等的空闲超时。客户端长时间没发数据,代理直接切断,后端根本不知道发生了啥。你可以在Nginx那边调proxy_send_timeout和proxy_read_timeout,或者让客户端定期发心跳包。
最后建议加上更细粒度的日志。你现在只监听uncaughtException和unhandledRejection,但HTTP连接断开可能走的是req.on('close')或者socket的end事件。建议在路由里加一层中间件:
这样至少能看到是不是大量请求在中途被关闭。结合服务器时间戳和客户端行为对比一下,基本就能定位是哪一环出的问题了。