date | tags |
---|---|
2021-03-11 |
javascript |
对于内存泄漏,一般来说是这样的步骤:
- 兜底方案,泄漏后重启实例,保证服务器配额健康。
- heapdump,分析具体泄漏原因。在兜底方案执行过频时,才需要紧急分析。
这里讲一下1。有两种常见的思路可以做到内存泄漏后重启:
- “自杀”,从实例内部监控,并且干掉自己。
- “他杀”,从实例外部监控进程,在实例超配额的时候干掉实例。
同样也有各自的手段,先说“自杀”,在nodejs中,可以用--max-old-space-size
,当然也可以直接监控内存指标。“他杀”更依赖于实际的runtime,docker或者pm2,方式可能不一样。在pm2中有一个参数叫max_memory_restart
,其他选型可能有其他选型的配置参数。max_memory_restart
有两个官方没有说明的点:
- 整个一套服务的所有实例内存占用是
max_memory_restart * 实例数
。 max_memory_restart
监控有30s的延迟,可以通过PM2_WORKER_INTERVAL
环境变量修改。
所以在计算配额的时候,需要考虑实例数max-old-space-size
也一样。并且因为延迟,所以针对内存的激增,pm2的反应是有些迟钝的,开发者需要评估是否需要调整监控的实时性,在实时性方面有可能“自杀”更好。实时性最好的应该是max-old-space-size
,不过需要关注老生区与rss
的差值是否过大,而导致整体配额估值不准。
对于worker的配额,计算也很简单:
- 单个worker限制配额
- 限制worker的个数
在node中,有两种不同的worker
- 基于thread的
- 基于process的
在内存方面,两者最大的区别是,worker_thread没有生成新的进程(不过有新的v8实例哈),rss是共通的。所以对于“他杀”形式的内存限制是一个利好,这样通过类似max_memory_restart
的参数,可以直接掌控所有worker。如果是process_worker,又是另外一种情况,还需要具体分析。
对于thread和process两种worker,都可以指定v8的参数,不过如果在外部有“他杀”程序,自毁也只能算提高实时性了,没看到特别有优越性。
- 建议使用外部程序监控内存
- 注意node实例数对内存配额计算的影响
- 注意外部监控的延迟
- 特别在意实时性可在内部监控,注意老生区监控可能导致的偏差
- 建议使用thread_worker,共用process以达到rss统筹监控