Table of Contents

0. 前言

知其然,知其所以然。作为后端程序,如果对所用的工具没有一定程度的了解,还真不敢放到线上进行运行。否则出了问题,如何解决都没谱,到时候可是线上事故。

本文主要在于以下几个方面,不局限于狭义的profileprofiler

  • Node 的性能Metrics:到底哪些进程指标是我们需要关心需要监控的
  • Node 的Profiler:如何对进程进行profile,获取核心metrics
  • Node 的GC:Memory以及GC相关的知识点,以及如何进行profile和观察,当然也需要关注memory leak及如何查找问题

版本信息

本文行文依据的Node版本,及所有范例的运行环境为:

Node version:
v8.4.0
Node v8 version:
6.0.286.52

本文撰写时候最新的LTS版本为:

v8.9.4

Node的Changelog可以在这里找到

一般只要版本差异不要太大,信息的可靠性都应该没有问题。但如果版本差异过大,请自行进行信息修正,毕竟Node的发展实在是太快。

1. 内存

2. 资料

资料我都放在前面,方便直接打开深度阅读。

2.1 Node相关

2.2 V8 & 内存

2.3 Chrome Dev Tool

2.4 专栏 & 博客

石墨文档技术酒馆

3.3 内存Metrics API

3.3.1 process.memoryUsage

  • rss:node进程总内存占用量
  • heapTotal:总堆内存占用量(已申请下来的)
  • heapUsed:实际堆内存使用量
  • external:扩展等外部程序的内存占用量

常用来查看基础的内存信息,特别是rss很有用。

3.3.2 require(“v8”).getHeapStatistics

  • total_heap_size:总堆内存占用量(已申请下来的),同process.memoryUsage().heapTotal
  • total_heap_size_executable:字节码、优化后的代码等可执行的内容占用的内存量
  • total_physical_size:找到部分解释说是Commited size,测试下来该值
    • used_heap_size < total_physical_size < total_heap_size
    • Committed memory is, essentially, all the memory which has been allocated by applications, whether it’s used or not.
  • total_available_size:剩余可用的堆内存量,包括尚未向操作系统申请的部分,其实就是heap_size_limit - used_heap_size
  • used_heap_size:实际堆内存使用量,同process.memoryUsage().heapUsed
  • heap_size_limit:最大可用堆内存(上限)
  • malloced_memory:实际测试是一个很小的值,有解释说是:current amount of memory, obtained via malloc
  • peak_malloced_memory:没搜到任何说明,有必要可以读下node源码
  • does_zap_garbage:覆盖堆垃圾的模式的开关

常用来查看堆上限大小。

3.3.3 require(“v8”).getHeapSpaceStatistics

按内存空间分类space种类不同,给出不同空间的内存使用状况统计。实用性不大,一般来说实际使用中需要关心的其实只有old space,且仅仅只有large object space。

3.3.4 top & ps

使用系统ps命令更快获取进程的内存占用情况:

ps -p $(pgrep -lfa node grep leak-and-gc.js awk ‘{print $1}’) -o rss,vsz

以及:

top -pid $(pgrep -lfa node grep leak-and-gc.js awk ‘{print $1}’)

3.5 内存泄露 & Chrome Dev Tool

3.5.1 范例

内存泄露可以使用下面5.1里的脚本进行试验。

3.5.2 查找问题

使用node的inspector来进行运行状态分析(当然,这工具可以做更多的事情)。关于Chrome Dev Tool,可以看官方教程

DEBUG=* node –inspect xxx.js

然后打开浏览器chrome://inspect/,找到你的脚本进行调试。

在打开的分析面板里,选中Memorytab,一共有3个选项可以操作:

  • Take heap snapshot
    • 获取node进程的堆快照
    • 点击之后需要等一段时间采集数据,然后就可以看到heap数据
    • 这个选项信息最全,一般是最常用的内存观察选项
    • 一般来说按最右边的Retained Size从大到小排序,就找到很有用的信息了
  • Record allocation profile
    • 以内存使用者的角度查看内存的分配情况
    • 在需要知道内存使用大户是哪个部分的业务的情况下很有用
    • 一样需要点击之后等一段时间进行采集
  • Record allocation timeline
    • 以时间轴为单位查看单位时间内的内存分配量
    • 在需要知道node的内存与时间关系的情况下很有用

在线上运行时有的时候如果需要看堆快照的话,可以使用第三方库bnoordhuis/node-heapdump在runtime使用代码导出快照。然后使用Chrome Dev Tool打开这个快照文件来查看内容。

Chrome Dev Tool可以加载多个堆快照,并对他们进行比对分析,这对内存量增长变化的分析非常有用。可以在程序里隔一定时间获取一次堆快照,然后线下慢慢分析。

更详细的可以看博客:

3.6 核心内存Metrics

3.6.1 Node内存

  • rss:node进程总内存占用量
  • heapTotal:总堆内存占用量(已申请下来的)
  • heapUsed:实际堆内存使用量
  • external:扩展等外部程序的内存占用量
  • heapSizeLimit:堆内存上限

按空间分类的堆内存信息可以酌情收集,如果有需要分析单独的新生代老生代内存情况的话。

3.6.2 Node GC

  • gcType:GC类型,一般来说新生代的scavenge回收可以忽略,这个类型GC的量级及可优化性都比较低
  • gcPause:GC中断,需要按不同GC类型进行分类收集,老生代的markSweepCompact数据最为关键
  • allocationRate:新内存分配下来的速率,bytes/second
  • promotionRate:内存从新生代到老生代的晋升速度,bytes/second

4. 性能知识点 - EventLoop

5. 工具

5.1 内存泄露 || 内存正常 范例脚本

为了观察内存泄露和GC日志,需要一个范例运行的脚本,我这里制作了一个:

5.2 GC解析管道脚本

5.3 NIM(Node.js 调试管理工具)

可在node进程使用--inspect flag时,自动打开chrome的调试tab。

EOF