为什么需要性能监控?聊聊Node.js性能监控
已收录为什么需要性能监控?下面本篇就来带大家了解一下Node.js性能监控,希望对大家有所帮助!
node.js极速入门课程:进入学习 Node作为Javascript在服务端的一个运行时(Runtime),极大的丰富了Javascript的应用场景。 但是Node.js Runtime本身是一个黑盒,我们无法感知运行时的状态,对于线上问题也难以复现。 因此性能监控是Node.js应用程序「正常运行」的基石。不仅可以随时监控运行时的各项指标,还可以帮助排查异常场景问题。 性能监控可以分为两个部分: 性能指标的采集和展示 性能数据的抓取和分析 从上图可以看到目前主流的三种Node.js性能监控方案的优缺点,以下是简单介绍这三种方案的组成: Prometheus AliNode 通过 通过 从上图可以看出, 通过 堆内存空间先划分为空间(space),空间又划分为页(page),内存按照1MB对齐进行分页。 New Space:新生代空间,用来存放一些生命周期比较短的对象数据,平分为两个空间(空间类型为 Old Space:老生代空间,用来存放 Code Space:存放v8 JIT编译后的可执行代码 Map Space:存放Object指向的隐藏类的指针对象,隐藏类指针是v8根据运行时记录下的对象布局结构,用于快速访问对象成员 Large Object Space:用于存放大于1MB而无法分配到页的对象 v8的垃圾回收算法分为两类: 前提: 触发时机:当 步骤: 在 发现存活(可达)对象 当复制结束时, 交换 适用于回收频繁,内存不大的对象,典型的空间换时间的策略,缺点是浪费了多一倍的空间 三个步骤:标记、清除、整理 触发时机:当 步骤: Marking(三色标记法) Sweep Compact 在最开始v8进行垃圾回收时,需要停止程序的运行,扫描完整个堆,回收完内存,才会重新运行程序。这种行为就叫全停顿( 虽然新生代活动对象较小,回收频繁,全停顿,影响不大,但是老生代存活对象多且大,标记、清理、整理等造成的停顿就会比较严重。 这个理念其实有点像React框架中的Fiber架构,只有在浏览器的空闲时间才会去遍历Fiber Tree执行对应的任务,否则延迟执行,尽可能少地影响主线程的任务,避免应用卡顿,提升应用性能。 由于v8对于新老生代的空间默认限制了大小 因此 由于GC日志比较原始,还需要二次处理,可以使用AliNode团队开发的v8-gc-log-parser 对于运行程序的堆内存进行快照采样,可以用来分析内存的消耗以及变化 生成 使用heapdump 使用v8的heap-profile 使用nodejs内置的v8模块提供的api 生成的 默认的视图是 当发现 还有 对于运行程序的CPU进行快照采样,可以用来分析CPU的耗时及占比 生成 这是采集5分钟的CPU Profile样例 生成的 默认的视图是 当发现 当应用意外崩溃终止时,系统会自动记录下进程crash掉那一刻的内存分配信息,Program Counter以及堆栈指针等关键信息来生成core文件 生成 获取 从监控可以观察到堆内存在持续上升,因此需要堆快照进行排查 根据 从代码中可以看到虽然 常见的内存泄漏有以下几种情况: 因此在上述这几种情况时,一定要谨慎考虑对象在内存中是否会被自动回收,不会被自动回收的话,需要手动进行回收,比如手动把对象设置为 至此,本文已经对整个Node.js的性能监控体系进行了详细的介绍。 首先,介绍了性能监控解决的问题,组成部分以及主流方案的优缺点对比。 然后,针对两大部分性能指标和快照工具进行了具体的介绍, 最后,从观察、分析、排查再现一个简单的内存泄漏案例,并总结了常见内存泄漏的情况和解决方案。 希望这一篇文章能够帮助大家对整个Node.js的性能监控体系有所了解。 更多node相关知识,请访问:nodejs 教程! 以上就是为什么需要性能监控?聊聊Node.js性能监控的详细内容,更多请关注php中文网其它相关文章!为什么需要性能监控
组成部分
方案对比
性能指标
CPU
process.cpuUsage()
可以获取当前进程的CPU耗时数据,返回值的单位是微秒Memory
process.memoryUsage()
可以获取当前进程的内存分配数据,返回值的单位是字节rss
包含代码段(Code Segment
)、栈内存(Stack
)、堆内存(Heap
)Heap
v8.getHeapStatistics()
和v8.getHeapSpaceStatistics()
可以获取v8堆内存和堆空间的分析数据,下图展示了v8的堆内存组成分布:semi space
):from space
,to space
New Space
晋升的对象GC
Mark-Sweep-Compact
算法,用于老生代的对象回收Scavenge
算法,用于新生代的对象回收Scavenge
New space
分为from
和to
两个对象空间New space
空间满了from space
中,进行宽度优先遍历Old space
to space
中to space
中只有存活的对象,from space
就被清空了from space
和to space
,开始下一轮Scavenge
Mark-Sweep-Compact
Old space
空间满了marking queue
(显式栈)中,并将这些对象标记为灰色marking queue
pop
出来,并标记为黑色push
到marking queue
上,如此往复Old space
的一端,这样清除出来的空间就是连续完整的Stop-The-World
Stop-The-World
)优化策略
空间调整
New space
默认限制:64位系统为32M,32位系统为16MOld space
默认限制:64位系统为1400M,32位系统为700Mnode
提供了两个参数用于调整新老生代的空间上限--max-semi-space-size
:设置New Space
空间的最大值--max-old-space-size
:设置Old Space
空间的最大值查看GC日志
node
也提供了三种查看GC日志的方式:--trace_gc
:一行日志简要描述每次GC时的时间、类型、堆大小变化和产生原因--trace_gc_verbose
:展示每次GC后每个V8堆空间的详细状况--trace_gc_nvp
:每次GC的详细键值对信息,包含GC类型,暂停时间,内存变化等快照工具
Heapsnapshot
生成方式
.heapsnapshot
文件有以下几种方式:v8.getHeapSnapshot()
v8.writeHeapSnapshot(fileName)
分析方法
.heapsnapshot
文件,可以在Chrome devtools工具栏的Memory,选择上传后,展示结果如下图:Summary
视图,在这里我们要关注最右边两栏:Shallow Size
和 Retained Size
Shallow Size
:表示该对象本身在v8堆内存分配的大小Retained Size
:表示该对象所有引用对象的Shallow Size
之和Retained Size
特别大时,该对象内部可能存在内存泄漏,可以进一步展开去定位问题Comparison
视图是用于比较分析两个不同时段的堆快照,通过Delta
列可以筛选出内存变化最大的对象Cpuprofile
生成方式
.cpuprofile
文件有以下几种方式:分析方法
.cpuprofile
文件,可以在Chrome devtools工具栏的Javascript Profiler
(不在默认tab,需要在工具栏右侧的更多中打开显示),选择上传文件后,展示结果如下图:Heavy
视图,在这里我们看到有两栏:Self Time
和Total Time
Self Time
:代表此函数本身(不包含其他调用)的执行耗时Total Time
:代表此函数(包含其他调用函数)的总执行耗时Total Time
和Self Time
偏差较大时,该函数可能存在耗时比较多的CPU密集型计算,也可以展开进一步定位排查Codedump
生成方式
.core
文件的三种方法:ulimit -c unlimited
打开内核限制node --abort-on-uncaught-exception
node启动添加此参数,可以在应用出现未捕获的异常时也能生成一份core文件gcore <pid>
手动生成core文件分析方法
.core
文件后,可以通过mdb、gdb、lldb等工具实现解析诊断实际进程crash的原因llnode `which node` -c /path/to/core/dump
案例分析
观察
分析
heapsnapshot
可以分析排查到有一个newThing
的对象一直保持着比较大的内存排查
unused
方法没有调用,但是newThing
对象是引用自theThing
,导致其一直存在于replaceThing
这个函数的执行上下文中,没有被释放,这就是典型的由于闭包产生的内存泄漏案例小结
null
、移除定时器、解绑事件监听等总结
声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
程序员必备接口测试调试工具:点击使用
声明:本文转载于网络,如有侵犯,请联系545125923@qq.com删除