OurJS


OurJS-我们的JS, 我们的技术-IT文摘; 专注JS相关领域;
我们热爱编程, 我们热爱技术;我们是高大上, 有品味的码农;

欢迎您订阅我们的技术周刊


我们会向您分享我们精心收集整理的,最新的行业资讯,技术动态,外文翻译,热点文章;
我们使用第三方邮件列表向您推送,我们不保存您的任何个人资料,注重您的隐私,您可以随时退订,

欢迎分享您的观点,经验,技巧,心得

让我们一起找寻程序员的快乐,探索技术, 发现IT人生的乐趣;


本网站使用缓存技术每次加载仅需很小流量, 可在手机中流畅浏览;
如果您发现任何BUG,请即时告知我们: ourjs(at)ourjs.com

Debug调试Node.JS:我们是如何定位内存泄漏和无限循环的


分享到
分类 JS学习   关键字 Node.JS   发布 ourjs  1415413995687
注意 转载须保留原文链接,译文链接,作者译者等信息。  
在Storify,我们用Node.js驱动后台。

对于大多数生产环境上的问题(像未捕获的异常),我们使用日志来调试。然后我们看到了一些其他的BUG,像内存泄漏和无限循环,这些漏洞无法通过debugging工具来调试。

注* 关于在Node.JS中添加错误日志,可参考: 守护node.js

过去,当我们的服务变得很慢时,我们使用Monit 去重启他们。当我们上线了Livefyre之后,我们决定不要重启,尝试去修复这些缺陷。经过几个月的尝试,我们在Node.JS的调试技巧方面学到了很多。

内存泄漏


几个月以前,我们已经知道程序有内存泄漏,这会引起我们的服务器强制自动重启。因为我们使用了大约60个npm 模块 ,这个BUG也有可能是从这些模块里产生的,因此找到泄漏点是不太可能的。

我们的同事@devongovett决定去修这个BUG,但是他不知道从何开始。

Devon创建了一台服务器去记录Node.JS的内存使用情况。他的第一个发现是在一条查询query执行后,几个对象被遗留了下来。下一步是将大量的Mongoose注释掉去寻找泄漏点。最终他找到了罪魁祸首。

“我认为这纯碎是运气”

这个调试经验让我们坚信我们需要使用更好的调试工具。

CPU占用率


我们的服务会偶尔当机几分钟。@tjfontaine Node.js项目的主管开始解决调试工具的问题,他建议我们试试MDB 。在阅读了这篇文章之后,我们开始玩这个工具了。

首次尝试


我使用gcare去获取核心转储(core dump),上传到Mana并开始分析。我的第一个分析很全面,但是我无法理解这个进程在干什么。

[ 00007fffe4967160 0x7f7a24ced619() ]
00007fffe496a1d0 uv__io_poll+0x148()
00007fffe496a230 uv_run+0xd8()
00007fffe496a2b0 _ZN4node5StartEiPPc+0x150()
0000000000000000 0x7f7a24c1e76d()

我在进程没有干什么任何事情的时侯捕获到了。


Node.js在等待事件发生时就会干这个。


最扯蛋的是gcare在你的程序崩溃的时侯进程了转储捕获(capture the dump)。这里有几个选项可以获取有用的跟踪。

在一段特定的代码处引导核心

process.abort()

在未捕获异常时引导核心

node --abort-on-uncaught-exception app.js

当CPU楔入(wedging)时杀死进程

kill -ABRT $pid


我们第一个有用的跟踪


通过使用 kill -ABRT method,我最终可以获取到一个好的跟踪栈。

我会只关注最重要的部分,但是你可以在这里看到整个栈。

> 00007ffffd09c0c0::jsstack
[...]
7ffffd09c7c0 0x3bdddc420285 inlineContent (e8477f4cc01)
7ffffd09c810 0x3bddc784e83d juice (e8477f4c9b9)
[...]
7ffffd09c948 0x3bddc4fb80f0 renderWrapper (270dfadc0769)
[...]
7ffffd09cdb8 0x3bddc7f2858b forEach (28a6e1015579)
[...]
7ffffd0a0ac0 node::Start+0x172

通过这个跟踪,我们开始注意Juice, 这是我们用来为RSS订阅源生成内联CSS的一个库(注* 邮件一般无法外联CSS样式)。我们只在Webapp代码里使用了一次。像下面这样:

async.forEach(stories, function(story, cb) {
    res.render(‘story/_minimal’, {
        //…
    }, function(e, html) {
        if (e) return cb(e);
        var description = juice(html, someCss);
        // …
    });
}, callback);

通过这个,我现在可以在本地重现这个挂起了。最终的研究我们发现问题出现在了Jsdom ,这个库在处理大量HTML文档时会非常慢。相比修复Jsdom,我们开始寻找快一点的模块。通过使用 Cheerio 和 Styliner 我们现在可以将处理过程压缩到3秒以内,但是Juice需要大概5分钟。

结论


我希望用这个工具找到mongoose的泄漏。现在我们可以直接找到bug,不需要猜了。

有些漏洞无法在非生产环境发现。找到一种可以在生产环境检测程序工作的工具非常重要。

现在我们在重启前都会使用Monit去自动检测核心转储:

stop program = “/bin/bash -c ‘/bin/kill -ABRT `/bin/cat <%= processpidfile %>`’”

然后我们将Manit的日志跟Hipchat连在一起。现在我们明白重启时什么发生什么。

希望这篇文章对你有所帮助。
原文地址: 点此
社区评论 ( Beta版 )
OnceDoc 您自己的企业内容管理系统——文档、流程、知识库、报表、网盘All In One

访问404页面,寻找丢失儿童
 热门文章 - 分享最多
  1. 我们不需要JavaScript框架
  2. 将GO编绎成JavaScript,用GO语言来写前端代码
  3. Nginx的大计划:将原生支持JavaScript
  4. 不需要密码的登录
  5. Google收购Firebase,Fire加入谷歌云平台
  6. Go语言实例教程基础语法篇(一)
  7. SpiderMonkey的JavaScript引擎[Firefox]性能超越V8[Chrome]
  8. 理解JavaScript中的事件路由冒泡过程及委托代理机制
  9. Redis集群,不再雾里看花
  10. Angular.JS出了什么问题?
  11. AirJD-简单好用的免费建站工具

 相关阅读 - JS学习
  1. 理解JavaScript中的事件路由冒泡过程及委托代理机制
  2. 用JavaScript制作HTML5动画基础
  3. Node.js 包教不包会
  4. 使用Javascript开发OS X应用程序
  5. Node程序中的设计模式
  6. 制作canvas游戏
  7. 5个经典的前端面试问题
  8. 拿什么守护你的Node.JS进程: Node出错崩溃了怎么办?
  9. 合并JavaScript数组的N种方法
  10. 内存管理技巧:如何避免JavaScript的内存泄露

 关键字 - Node.JS
  1. node.js中fs.stat里的atime,mtime,ctime,birthtime在debian下的更新规则与区别
  2. NodeJS的DNS使用:域名解析,MX记录查询,SPF反垃圾邮件测试
  3. 在nodejs中使用Redis缓存和查询数据及Session持久化(Express)
  4. 是什么让Node.js比Java更快?为什么NodeJS这么快?
  5. 用纯Node.JS弹出Windows系统消息提示框(MessageBox)
  6. 利用Windows注册表将你的Node.JS程序添加到右健菜单直接运行
  7. Node.js中的通用基础设计模式
  8. Node.JS中如何判断递归嵌套的所有回调函数已经执行完毕,以读取目录下所有文件为例:计数比Promise方式快将近一倍
  9. Node.js网页抓取:一个最简单的http请求客户端示例(request client)
  10. 6款基于Node.JS的开源内容管理和静态网站生成系统

 欢迎订阅 - 技术周刊

我们热爱编程, 我们热爱技术; 我们是高端, 大气, 上档次, 有品味, 时刻需要和国际接轨的码农; 欢迎您订阅我们的技术周刊; 您只需要在右上角输入您的邮箱即可; 我们注重您的隐私,您可以随时退订.
加入我们吧! 让我们一起找寻码农的快乐,探索技术, 发现IT人生的乐趣;


 关注我们

我们的微信公众号: ourjs-com
打开微信扫一扫即可关注我们:
IT文摘-程序员(码农)技术周刊

ourjs官方微信号