Nodejs 基于TCP的服务器用PM2运行后资源暴涨

Nodejs 基于TCP的服务器用PM2运行后资源暴涨

主要实现的是一个聊天登陆功能的服务器,原来用forever运行没看到什么资源占用,如下

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                   
20558 root      20   0  758m  60m 5760 S  3.0  0.4   0:15.91 node 

用了pm2启动并查看内存资源,差不多10个小时内存飙升到1.5g,cpu持续在8%平均,本来以为代码的memory leak,大量找资料,然后改写代码**(其实还是没找到哪里会memoryleak,只是把一些回调函数从临时改成成员函数,把收发socket数据的用户业务逻辑对象改成了资源池可复用,尽量减少创建新的buffer,不过buffer的创建不可避免因为要解决粘包问题)**

做了这些后,一点也没好效果啊,然后重新改用forever运行就又没这么变态的占用。 我没用cluster就是单进程跑的。 大家有谁有这方面经验么,反正用pm2的web检测看就是内存几秒涨一点,非常快


2 回复

Nodejs 基于TCP的服务器用PM2运行后资源暴涨

背景

主要实现的是一个聊天登录功能的服务器。使用forever运行时,没有观察到明显的资源占用。但是切换到PM2运行后,发现内存资源迅速增长,CPU占用也持续较高。

现象描述

  • 使用forever运行时:

    PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                   
    20558 root      20   0  758m  60m 5760 S  3.0  0.4   0:15.91 node
    
  • 使用PM2运行后:

    • 10小时内内存从几百MB增长到1.5GB。
    • CPU持续在8%左右波动。
    • PM2的Web界面显示内存每几秒钟增长一次,增长速度非常快。

尝试的优化措施

  • 把一些回调函数从临时函数改为成员函数。
  • 将收发socket数据的用户业务逻辑对象改成了资源池可复用。
  • 尽量减少创建新的Buffer对象,但由于粘包问题,仍然需要创建新的Buffer对象。

问题分析

经过上述优化措施后,资源占用依然很高,因此怀疑可能是PM2本身或配置问题导致的内存泄漏。

解决方案

  1. 检查PM2配置

    • PM2默认配置可能不适合某些应用,可以尝试调整配置。
    • 示例配置文件:
      {
        "apps": [
          {
            "name": "chat-server",
            "script": "./server.js",
            "max_memory_restart": "1G",
            "instances": 1,
            "exec_mode": "fork"
          }
        ]
      }
      
  2. 增加垃圾回收频率

    • 可以通过修改Node.js参数来增加垃圾回收的频率。
    • 示例启动命令:
      pm2 start server.js --node-args="--max-old-space-size=4096 --expose-gc" --watch
      
  3. 使用cluster模式

    • 单进程模式可能会导致资源占用过高,可以尝试使用cluster模式来提高性能和稳定性。
    • 示例代码:
      const cluster = require('cluster');
      const os = require('os');
      
      if (cluster.isMaster) {
        for (let i = 0; i < os.cpus().length; i++) {
          cluster.fork();
        }
      } else {
        // TCP Server code here
        const net = require('net');
        const server = net.createServer((socket) => {
          socket.on('data', (data) => {
            console.log(`Received data: ${data.toString()}`);
            socket.write(data);
          });
        });
      
        server.listen(3000, () => {
          console.log('Server is listening on port 3000');
        });
      }
      
  4. 监控和调试

    • 使用工具如memwatch-nextheapdump等来监控内存使用情况。
    • 示例代码:
      const memwatch = require('memwatch-next');
      memwatch.on('stats', function(stats) {
        console.log(stats);
      });
      

通过以上措施,可以有效降低资源占用,并提高服务器的稳定性和性能。如果问题依然存在,建议进一步深入分析代码和系统配置。


根据你的描述,使用PM2运行Node.js TCP服务器时,发现内存占用异常增加。这种情况可能与PM2的运行机制或程序内部某些未被注意到的地方有关。这里有一些可能的原因和建议:

  1. PM2缓存机制:PM2有自身的缓存机制,可能会导致内存占用异常增加。你可以尝试使用pm2 flush清除缓存。

  2. 内存泄漏检查

    • 使用工具如memwatch-next来检测内存泄漏。
    • 确保所有事件监听器都被正确移除,特别是在处理TCP连接时。
    • 避免全局变量的滥用,尤其是那些引用了大量数据的对象。
  3. 资源池优化:你已经提到对资源池进行了一些优化,确保对象池中的对象不会保存状态,以避免累积数据。

  4. 使用弱引用:如果需要保留某些对象引用但又不想阻止垃圾回收,可以考虑使用weak模块来管理这些引用。

  5. 日志分析:增加详细的日志记录,观察在内存增加时哪些操作频繁发生。

  6. PM2配置调整

    • 尝试调整PM2的参数,如--max-memory-restart来自动重启内存超标的进程。
    • 使用pm2 start app.js --max_memory_restore 1G限制内存增长。

示例代码片段(用于检测内存泄漏):

const memwatch = require('memwatch-next');

memwatch.on('leak', (info) => {
    console.error('Memory Leak Detected:', info);
});

// 在合适的位置添加监听器移除逻辑
server.on('connection', (socket) => {
    socket.on('data', (data) => {
        // 处理数据
    });
    
    socket.on('end', () => {
        // 移除监听器
        socket.removeAllListeners();
    });
});

以上建议希望能帮助你解决问题。如果内存泄漏仍然存在,可能需要进一步详细检查代码逻辑。

回到顶部