终于找到写的 NodeJS 微服务都支持不到 1 天的原因了

2017-10-08 07:47:37 +08:00
 doubleflower

前情: https://www.v2ex.com/t/392238

从 Python 转过来写了几个 Node 微服务全它妈的跑一天就 Out of memory,之前暂时用了高内存就主动自杀的补丁顶着。

然后这二天查了相关文章,发现 Node 的 gc 和 Python 是完全不同的,Python 的 gc 相当主动(可能和引用计数有关),一有无用内存当场就回收了,而 Node 不会(类似于 Java )。 默认 64 位机器 Node gc 认为你有 1.4G 内存,到这个点之前 gc 干活相当偷懒,可是我都是跑在 1G 小鸡上的,所以就 BOOM 了。

所以你是在内存小于 1G 的机器上跑比较忙的需长时间运行的程序,需要在 Node 命令行上加上 --max_old_space_size=384 --optimize_for_size 这二参数,我跑了几天内存都没过 400M,而以前没多长时间就超 700M 引起 OOM。

14234 次点击
所在节点    Node.js
38 条回复
lilydjwg
2017-10-08 16:09:51 +08:00
@workwonder #20 你可以看看 gc.garbage 里有没有东西。然后试试 tracemalloc 和 objgraph、memory_profilter 之类的工具。我有一些长期工作的 Python 程序,仅有一个偶尔会出现内存泄漏(并且需要数月才能明显观察到)。
shiny
2017-10-08 16:14:45 +08:00
我写的 node 服务经常跑在 1G 或者更小的鸡上也没遇到过这个问题,只处理过内存泄露的情况。
workwonder
2017-10-08 16:16:39 +08:00
@lilydjwg 我的 Python 程序都是靠自杀+接力来实现长期运行的,搞不搞笑,我觉得很羞辱,曾经拒绝启用这样的参数(比如 gunicorn 或 uwsgi 里面),后来不得不妥协了。
lilydjwg
2017-10-08 16:21:00 +08:00
@workwonder #23 还好吧,nodejs 和 php-fpm 都是这么干的。
doubleflower
2017-10-08 17:42:36 +08:00
我想要说明的是,不是我写的所有 node 应用都撑不到一天。

二个 HTTP Web 服务可以撑相当长时间(一个月起)。

而另三个队列处理的就不行。不过逻辑和 http server 有点不同,主要是处理响应比较慢,不是当场返回结果,而是会在内部有一个内存列队,并用了大量 Promise 异步(刚转到 node 这点很爽,用得没有节制)。我一开始以为用的异步太多了导致的内存泄漏,现在看来并不是。

猜想是简单的 http 服务请求内存分配释放很快,总是在新生代。而处理队列+大量 promise 基本都是在老生代,所以有区别。
chenqh
2017-10-08 17:50:32 +08:00
@workwonder 你的 django 程序是不是用了 celery?可能是 celery 配置不当导致的内存泄漏,你有没有设置
BROKER_POOL_LIMIT = 0 这个东西,设置为 0 会内存泄漏
workwonder
2017-10-08 18:33:26 +08:00
@chenqh 我刚举的例子,Django 项目没用 celery,flask 项目配合 celery 使用的。
多谢你的设置指示!
chenqh
2017-10-08 18:44:51 +08:00
@workwonder 好吧,那我就不知道了,有可能真的是 py3.5 的问题吧
janxin
2017-10-08 19:51:12 +08:00
@workwonder 你这个应该也是看具体情况具体分析了,我某个线上应用目前运行 200+天没有大量的内存泄漏情况出现...
workwonder
2017-10-08 19:58:39 +08:00
@janxin 我那个 Django 应用的并发量和日访问量都很小,问题是数据量很大,经常是上万条记录(再加上关联查询)一起 load 到前端,实际上一两次这样的请求消耗的内存总量并不大,要命的是内存不及时释放(或者根本不释放),持续上涨一直到爆。
workwonder
2017-10-08 20:04:42 +08:00
@workwonder 我也知道 Django 可以用迭代器模式遍历 queryset,这样能大大优化内存占用。但我觉得这有点自欺欺人(减少单次请求的内存消耗,并没有实际解决内存的不释放问题,顶多是缓兵之计),而且我是配合 drf 使用,改成迭代器模式不太自然。
dzmcs
2017-10-09 01:27:09 +08:00
我都半年没动过 node 写的程序了,感觉挺稳定的
calease
2017-10-09 10:54:05 +08:00
python 那个不是泄露。python interpreter 不会把从系统申请到的内存返回给系统,所以给人“越用占内存越多”的感觉。比如你写一个最大支持 1G 上传的服务器,并且用最大 25 个 threads,那么高峰时期你 python process 的最大内存占用会是 25G+,但并不会增大到无限多。所以在用 python 写大内存需求的程序时需要仔细考虑,如果内存 intensive 的操作要加锁。
marvinwilliam
2017-10-09 12:40:16 +08:00
你这个内存泄漏没处理好吧? 我们这的项目跑起来内存占用一直在一个稳定的范围之内啊.
powerfj
2017-10-09 17:43:37 +08:00
额, 应该是哪个模块泄漏了, 理论上你的服务正常跑的话不可能内存一直涨的, 我的服务都是几个月不重启都不会内存炸的..
doubleflower
2017-10-09 17:46:36 +08:00
@powerfj 并不是你说的这样,因为我做了这个设置后内存一直都没有涨。没做这前一直会涨到 OOM。
imherer
2017-10-09 21:20:47 +08:00
@doubleflower #25 一样。 之前用 http 的东西跑个大半年都没任何问题,最近用 socket 做的内存涨的太快了,还在苦逼的查找问题中。。。
powerfj
2017-10-11 09:38:39 +08:00
@doubleflower 开始没仔细看, 大概明白你的意思了, 这么说就是 node 设置的最小的内存大小超过了你的服务器的内存最大值, 所以会存在这个问题.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/395867

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX