node内存终于溢出了
发布于 7 年前 作者 sumory 29857 次浏览 最后一次编辑是 3 年前
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory

#####表现:#####

  • 用100W条数据循环使用redis库建立索引(zadd)并初始化数据(hmset),到70万左右时速度急剧下降,最后内存溢出,在整个过程中node进程内存一直上升。

#####可能原因:#####

  • 每次循环都去redis建立索引并插入数据,并用multi提交,猜想是node事件(回调)太多,redis并没有处理完,一直在等待返回.
  • 按我的机器配置,将循环数据量降到10W内就不会出错,内存也不会一直暴涨

有谁使用过redis的nodejs库,并有类似的使用场景嘛?

26 回复

@suqian @Jackson 有没有类似经验啊?

如果你一直循环,io过程根本没有得到执行。

有执行,比如100W数据,可能执行到60几W的时候就溢出了,我猜想是不是node的事件太多了

@sumory 只有当脚本进入空闲的时候,才会执行callback脚本。如果你真的需要加入100W行数据,尝试通过setTimeout将插入操作分段,这样node才能执行callback过程,否则callback会始终积压,必然造成溢出

@zxc122333

  • 目前我就是把数据切分然后分批建立索引的;
  • 不知道还有没有从语言本身上处理以避免这个问题的,setTimeout不太优雅啊

@sumory 如果用到setTimeout 0的话可以用node的process.nextTick代替。

@zxc122333 @sumory zxc说到重点了,如果是0.8以上,可以尝试 Cluster

@jankuo 我这个过程只在初始化时使用,用cluster大材小用了

@jiangmiao nextTick是可以让进程有空闲去处理新事件,我想知道还有没有更好点的方案,让数据量大时node不至于卡死

其实我现在也遇到了和你差不多的问题,我这边是一个在线互动游戏,当用户数量达到一定数量的时候,有时会出现process out of memory的情况。我估计也是由于在socket.io接收到客户端请求的时候,后后台做了一些异步的操作(比如记录文本日志、调用webservice进行业务处理),导致nodejs一直没有时间去处理异步回调。

我想了一下,就算使用nextTip把异步调用推迟到下一次事件循环再处理。但还是避免不了这个问题啊,因为问题的产生是由于整个异步调用的过程被分为**‘调用’和‘回调’**2个步骤。其中‘回调’这个步骤只有nodejs线程‘有空’的时候才会来处理,换句话说,即使我们把‘调用’的时机推迟了,但是他执行完‘调用’后,仍然会去接着处理其他的请求,而导致有很多的‘回调’在堆栈中积压啊

  • 如果能手动的控制、或解除这些回调、又或有超时机制自动回收的话就好了
  • 我感觉回调处理这部分不在掌控(貌似没有API可以控制)中是异步带来的又一个问题,不好处理。

做个队列处理异步事情吧,要么就增加服务器增加吞吐量

我的想法是把需要异步处理的方法都做成可以批量执行的。比如写日志,可以一次写n条,后台业务处理也支持批量操作。然后维护一个异步请求队列,每次处理n条请求,减少系统异步回调堆栈的压力

我也有这样的情况! FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory

大循环里不要停的取数据。然后就挂掉了。

可以通过连接池控制下吧~

@snoopy 连接池?如何控制呢?

@sumory 就是访问数据库只打开固定数量的链接,多余的在后面排队。其实也就是队列功能,换个说法而已。node.js有这方面的模块的,我用的比较多的是generic-pool

@snoopy 嗯,你说的是数据库的啊,我也用generic-pool连mysql。我遇到的情况是node本身存在的,需要我们绕弯去解决的。

@sumory 看来目前没啥好办法,我是直截setTimeout 分批处理

@hades 你遇到的问题与我和sumory的不大一样,要从根本上解决异步调用的次数,而不是仅仅延后异步处理的时机

@sumory 不知道你服务器配置怎么样,扛不住的话在node前面增加负载均衡的设备或者软件吧

其实和回调无关

好吧,我的内存也终于溢出了⛷。 我的情况是

	for (i <- [1,  100w]) {
		req = http.request(options, callback)
		req.end()
	}

我试了下,假如是30w及以下基本都是ok的,但只要涉及100w基本都会OOM,怀疑是生成的req过多,而callback没有得到执行,一直堆积导致的,目前也在找有效的方法,暂时使用--max-old-space-size设置可以解决,但这样子总觉得不好。 node v4.3.1, CentOS 6.6, OS Memory 20G左右。

setTimeout 不是基于事件循环的吗?

回到顶部