Nodejs如何跟踪内存泄露(或者谁用过3rd-Eden/node-memcached)

Nodejs如何跟踪内存泄露(或者谁用过3rd-Eden/node-memcached)

最近加了memcached后发现线上的服务存在内存泄露,8G的内存基本跑个4,5天就吃光了,跟了几天没有什么实质进展 因为在去掉memcached后不存在内存泄露,所以怀疑是3rd-Eden/node-memcached造成的,也许是我使用方法不对。 代码比较简单

var memcached = require("memcached");
var mc = new memcached(config.memcache, {reconnect: 100, retries: 2, failures: 2, timeout: 300, failuresTimeout: 1000, minTimeout: 100, poolSize: 50});
mc.on('issue', function(details) {
    //todo
});
exports.get_user = function(req, data) { 
    var key = data.key;
    mc.get(key, function(err, item) { 
        if (item) {
            //应用逻辑
        } else {
            //从数据库读取后set
            //应用逻辑
        }       
    });
}

在小访问量的情况下的确发现不了问题,用ab压测几十万条请求也没问题,内存吃个几百M基本就稳定了

但是线上环境,每台机器一天50万+的请求量,跑个4,5天内存就光了 我试过将memcache的相关代码去掉后内存不会泄露,然后只保留

var memcached = require("memcached");
var mc = new memcached(config.memcache, {reconnect: 100, retries: 2, failures: 2, timeout: 300, failuresTimeout: 1000, minTimeout: 100, poolSize: 50});

也不会泄露,

然后只将memcache的监听去掉会泄露,只将memcache的set部分去掉也会泄露,所以怀疑get在大量请求的情况下会有问题? 但看了下他代码,,,感觉无从下手。。。不知道怎么去跟踪这个问题。


8 回复

Node.js 如何跟踪内存泄露(或者谁用过 3rd-Eden/node-memcached)

背景

最近在项目中引入了 memcached 后,发现线上服务存在内存泄露问题。服务器配置为 8GB 内存,运行 4 到 5 天后内存就被耗尽。初步检查发现,在移除 memcached 相关代码后,内存泄露现象消失。

疑点

怀疑是由于 3rd-Eden/node-memcached 引起的内存泄露。以下是相关代码片段:

var memcached = require("memcached");
var mc = new memcached(config.memcache, {
    reconnect: 100,
    retries: 2,
    failures: 2,
    timeout: 300,
    failuresTimeout: 1000,
    minTimeout: 100,
    poolSize: 50
});

mc.on('issue', function(details) {
    // TODO: Handle issues here
});

exports.get_user = function(req, data) {
    var key = data.key;
    mc.get(key, function(err, item) {
        if (item) {
            // 应用逻辑
        } else {
            // 从数据库读取后 set
            // 应用逻辑
        }
    });
}

分析

在低访问量情况下,使用 Apache Bench (ab) 进行压测并未发现问题。但在高访问量环境下(例如每台机器每天处理 50 万以上的请求),经过 4 到 5 天内存被耗尽。进一步测试发现:

  • 移除 memcached 相关代码后,内存不再泄露。
  • 只初始化 memcached 客户端时,内存不泄露。
  • 只有在添加 mc.getmc.set 操作时,内存泄露才会发生。

这表明 memcached 的某些操作可能是导致内存泄露的原因。

如何跟踪内存泄露

  1. 使用内存分析工具

    • Node InspectorChrome DevTools: 可以帮助你找到内存泄漏的具体原因。
    • Heap Snapshots: 可以捕获堆内存快照并比较它们,查看哪些对象没有被回收。
  2. 代码审查

    • 确认是否有未释放的引用或循环引用。
    • 确认是否正确关闭了 memcached 连接。
  3. 监控内存使用情况

    • 使用 process.memoryUsage() 函数监控内存使用情况。

示例代码:使用 Heap Snapshots 跟踪内存泄露

const memcached = require("memcached");

// 初始化 memcached 客户端
const mc = new memcached(config.memcache, {
    reconnect: 100,
    retries: 2,
    failures: 2,
    timeout: 300,
    failuresTimeout: 1000,
    minTimeout: 100,
    poolSize: 50
});

// 启动内存监控
function startMonitoring() {
    setInterval(() => {
        const memoryUsage = process.memoryUsage();
        console.log(`Memory Usage: ${memoryUsage.rss} bytes`);
    }, 1000);
}

// 获取用户信息
exports.get_user = function(req, data) {
    const key = data.key;
    mc.get(key, function(err, item) {
        if (err) {
            console.error('Error fetching from memcached:', err);
            return;
        }

        if (item) {
            // 应用逻辑
        } else {
            // 从数据库读取后 set
            // 应用逻辑
        }
    });
}

startMonitoring();

// 为了方便演示,这里模拟一些请求
for (let i = 0; i < 1000000; i++) {
    exports.get_user(null, { key: `test_key_${i}` });
}

总结

通过以上步骤可以有效地追踪内存泄露问题。如果仍然无法定位问题,建议进一步检查 memcached 客户端的文档和源码,确认是否有已知的内存泄露问题。


我用这个跟踪修复了request上传超大文件的memory leak漏洞

之前碰到过node-memcached的内存泄漏,这么久了还没修

换redis试下

我跟你的情况类似,压测都没问题,线上环境就会内存溢出,我没用node-memcached这个模块,反正这些第三方的模块很多都不省心,我之前找到node-mysql可能导致内存泄露的地方https://github.com/felixge/node-mysql/issues/797,估计也有不少人掉到这坑了

你用node-heapdump把堆打出来看看

根据你的描述,你怀疑是 3rd-Eden/node-memcached 导致的内存泄漏。为了跟踪内存泄漏问题,你可以采取以下几种方法:

1. 使用内存分析工具

可以使用一些内存分析工具来帮助诊断内存泄漏问题,比如:

  • MemWatchJS:用于检测Node.js中的内存泄漏。
  • Heapdump:生成Node.js进程的堆快照文件,以便后续分析。
  • Chrome DevTools:通过生成和分析V8引擎的堆快照来查找泄漏。

示例代码

const heapdump = require('heapdump');
const memcached = require("memcached");

var mc = new memcached(config.memcache, {reconnect: 100, retries: 2, failures: 2, timeout: 300, failuresTimeout: 1000, minTimeout: 100, poolSize: 50});

// 创建一个定时器定期生成堆快照
setInterval(() => {
    heapdump.writeSnapshot('./heapdump-' + Date.now() + '.heapsnapshot', function(err, filename) {
        console.log('Dump written to ' + filename);
    });
}, 60000);  // 每分钟生成一次堆快照

mc.on('issue', function(details) {
    console.error('Memcached issue:', details);
});

exports.get_user = function(req, data) { 
    var key = data.key;
    mc.get(key, function(err, item) { 
        if (err) {
            console.error('Error fetching from Memcached:', err);
            return;
        }
        if (item) {
            // 应用逻辑
        } else {
            // 从数据库读取后set
            // 应用逻辑
        }       
    });
}

2. 监控和日志

添加更多的监控和日志输出,记录Memcached的操作和错误信息,以便更好地定位问题。

示例代码

mc.on('issue', function(details) {
    console.error('Memcached issue:', details);
});

3. 检查配置参数

检查并调整 3rd-Eden/node-memcached 的配置参数,比如 poolSizereconnect 等,确保它们适合你的应用场景。

4. 更新库版本

检查是否有更新的库版本,新版本可能已经修复了内存泄漏问题。

总结

通过使用内存分析工具和增加监控日志,可以更有效地诊断和解决内存泄漏问题。如果你仍然无法解决问题,考虑向 3rd-Eden/node-memcached 的维护者报告问题,并提供详细的错误信息和代码片段。

回到顶部