为何要进行内存超限重启
在代码层面,我们有很多种方式来防止NodeJS在执行的过程中出现内存泄露。但是当业务逻辑复杂的情况下,很难做到完全无内存泄露。这时候,一个偷懒的办法就是要让服务进程在超过一定内存阈值的时候重启。
直接杀死进程的方式是不推荐的,因为会影响正在处理中的 request。在 cluster 模式下,node对每一个 fork 出的子进程提供了优雅的退出方式:
cluster
他会保证子进程退出前处理完所有正在进行中的 request。
所以,我们可以在内存超出一定阈值的时候,调用disconnect方法。
如何检测子进程内存占用量
使用usage模块可以检测进程内存占用量(PS,在 node 0.12 版本下未能安装,在 4.x 版本下可以):
usage.lookup(process.pid, function(err, result) {
if
});
在内存超限时重启
在内存超过一定阈值的情况下重启子进程的 cluster 模式下的进程管理的代码如下:
//in memory.js
代码里有两个注意点:
注意点A
其实这里是参考了 domain 的文档:Node.js v7.9.0 Documentation,我们这里设置若干秒后将进程推出。
但是我们发现,这里调用了 killtimer.unref(),这里是为了防止定时器的存在阻止程序退出(PS:国内几乎所有的书都在说 unref 的作用是阻止回调调用,其实不然,timer 的 unref 函数)。
注意点B
disconnect调用时,我们就要 fork 出新的子进程,但是有些情况下,进程会意外退出。在意外退出时,我们也要 fork 新的子进程补位,这时候就要区分到底是意外退出还是程序退出,否则就会 fork 冗余的子进程。
cluster 的官方文档有说明可以通过worker.suicide和worker.exitedAfterDisconnect来判断进程是否是意外退出,但遗憾的是,node 的某些中间版本因为 bug (比如 4.x)失去了对这两个flag的支持,所以这里我们通过自己设置标志位isSuicide来判断是否意外退出。
使用方法
直接调用 export 出的 run 方法,设置超限阈值,设置子进程服务,设置重启回调:
var
这里要注意的是,内存的阈值要低于总内存/进程数,要给重启时 fork 的新进程(因为那时候的老进程还未退出)以及系统上的其他服务留有内存空间。
最后一句话:重启大法虽然好,但是也要防止内存泄露。