Node.js SOCKS5代理单CPU轮流100%占用问题排查求助
排查Node.js SOCKS5代理长期运行后CPU占满问题的思路
我之前也碰到过类似的长期运行Node.js服务CPU突然飙满的情况,结合你的strace输出、性能分析数据和代码场景,给你几个针对性的排查方向:
1. 先揪出epoll_pwait异常循环的根源
你的strace里epoll_pwait占了99.76%的CPU时间,调用次数还特别多——这是典型的事件循环高频空转信号,大概率和未正确清理的套接字资源有关:
- 检查TCP/UDP套接字的关闭逻辑:不管是客户端断开、代理目标断开,还是请求处理失败,都要确保调用
socket.destroy()或者socket.end()彻底释放资源。尤其是UDP套接字,因为它是无连接的,很容易出现绑定后忘记释放的情况。 - 问题复现时用
ss -tulnp | grep node查看套接字状态:看看有没有大量CLOSE_WAIT/TIME_WAIT的TCP连接,或者一堆没关闭的UDP套接字,这些都是事件循环的“隐形负担”。
2. 排查Cluster模式下的子进程资源泄漏
你用Cluster.fork()创建了多实例,要考虑子进程是否存在资源累积的问题:
- 检查子进程里的全局变量:比如有没有用数组、Map存储请求上下文,却在请求结束后没清理?哪怕内存占用看起来正常,小对象的持续累积也可能触发事件循环的高频调度。
- 手动测试子进程:问题出现时,kill掉一个CPU占满的子进程,如果CPU立刻回落,说明这个子进程有泄漏,可以单独对它做针对性分析(比如用
node --inspect远程调试)。
3. 深入Node.js C++层定位问题
你的性能分析显示91.1%的时间花在C++层,syscall占了81%的ticks,说明问题出在原生IO处理部分:
- 开启事件追踪启动服务:用
node --trace-events-enabled --trace-event-categories=node.async_hooks,node.net,node.dgram启动,收集异步钩子和网络事件日志,长期运行后查看是否有大量未销毁的async资源(比如套接字句柄)。 - 用
perf做系统级分析:运行perf record -g -p <出问题的node进程PID>采样几分钟,再用perf report看调用栈,能直接定位到C++层里哪个函数在疯狂占用CPU,比如net模块的某个处理逻辑。
4. 检查SOCKS5协议处理的细节漏洞
SOCKS5的TCP转发和UDP关联逻辑很容易藏坑,有些错误处理不当会导致无限循环:
- 验证UDP关联的处理:客户端请求UDP关联后,你是否正确处理了数据包的转发和响应?有没有可能在数据包解析或转发逻辑里出现了死循环?
- 检查认证阶段的错误分支:如果客户端发送无效的认证请求,你是否正确关闭连接并释放所有相关资源?有没有某个错误分支里漏了清理套接字,导致事件循环一直处理这个无效的套接字事件?
5. 临时缓解方案
在找到根本原因前,可以先给Cluster加个自动重启机制:
const cluster = require('cluster'); const os = require('os'); if (cluster.isPrimary) { for (let i = 0; i < os.cpus().length; i++) { cluster.fork(); } // 子进程退出时自动重启 cluster.on('exit', (worker, code, signal) => { console.log(`Worker ${worker.process.pid} died, restarting...`); cluster.fork(); }); // 可选:定期检测子进程CPU占用,过高则主动杀死 setInterval(() => { for (const worker of Object.values(cluster.workers)) { worker.process.send({ type: 'checkCPU' }); } }, 60000); } else { // 子进程逻辑:监听CPU检查请求,超过阈值则退出 process.on('message', (msg) => { if (msg.type === 'checkCPU') { const usage = process.cpuUsage(); const cpuPercent = (usage.user + usage.system) / 1000 / 60; // 计算最近60秒的CPU占比 if (cpuPercent > 90) { process.exit(1); } } }); // 启动你的SOCKS5代理服务器 }
内容的提问来源于stack exchange,提问作者Koray Gocmen




