Node 案发现场揭秘 如何利用 GC 日志不修改代码调优应用性能

2018-10-23 admin

# GC 简介

GC 的全称是 garbage collection,它其实是一种自动内存管理机制,一般会由对应语言实现的垃圾回收器,在某些触发条件下对当前程序不再使用的对象内存进行回收处理。

在 Node.js 中则是由 V8 引擎负责 GC 操作,但是默认状态下相关的日志信息是关闭的,我们可以通过设置一系列 flag 来实时获取到不同级别的 V8 GC 日志信息:

  • trace_gc: 一行日志简要描述每次 GC 时的时间、类型、堆大小变化和产生原因
  • trace_gc_verbose: 结合 --trace_gc 一起开启的话会展示每次 GC 后每个 V8 堆空间的详细状况
  • trace_gc_nvp: 每一次 GC 的一些详细键值对信息,包含 GC 类型,暂停时间,内存变化等信息

GC 日志目前是文本格式输出的形式,需要大家获取到以后进行对应的按行解析处理,也可以使用 v8-gc-log-parser 直接进行解析处理,对这一块有兴趣的同学可以看 @joyeeCheung 在 JS Interactive 的分享: Are Your V8 Garbage Collection Logs Speaking To You?

今天的这个案例其实正是在 Node.js 性能平台 上借助于解析和展现 V8 的 GC 日志来进行不更改代码业务逻辑下的性能调优。

# 压测现象

事情源于我们的一位客户在项目上线进行压测时,CPU 100% 时单进程 QPS 在 100 上下浮动,想进行一些进一步的优化。首先想到的就是接入 Node.js 性能平台 并且在压测试做 CPU Profile 观察系统 CPU 耗费在什么地方:

可以看到 _tickDomainCallbackgarbage collector 在 CPU 的占比加起来高达 83%,而经过和用户沟通,发现 _tickDomainCallback 内部的耗费 CPU 高的逻辑分别是 typeorm 和自己的 controller 逻辑,typeorm 方面因为 api 变动的原因不太方便升级,controller 逻辑则是已经优化过了暂时没有提升的空间。

因此很自然的,我们会把进一步提升项目性能的目光放到 GC 阶段。这里在 3min 的 CPU 采样期间,GC 阶段的调用占比高达 27.5%,结合当时的性能平台监控数据,我们可以看到绝大部分都是 scavenge 阶段,此时继续进行线上压测,同时做 GC Trace 来获取更多 GC 阶段的详细信息:

在 GC Trace 结果分析图中,可以看到红圈起来的几个重要信息:

  • GC 总暂停时间高达 47.8s,大头是 scavenge
  • 3min 的 GC 追踪日志里面,总共进行了 988 次的 scavenge 回收
  • 每次 scavenge 耗时均值在 50 ~ 60ms 之间

# 进一步分析

上面对 GC Trace 结果的分析中,可以看到此次 GC 优化的点集中在 scavenge 回收阶段,即新生代的内存回收。那么通过翻阅 V8 的 scavenge 回收逻辑可以知道,这个阶段触发回收的条件是:semi space allocation failed

这样就可以推测,用户的应用在压测期间应该是在新生代频繁生成了大量的小对象,导致默认的 semi space 总是处于很快被填满从而触发 flip 的状态,这才会出现在 GC 追踪期间这么多的 scavenge 回收和对应的 CPU 耗费。面对这样的情况,我们是不是可以通过调整默认的 semi space 的值来进行优化呢?

# 尝试优化

## I. semi space 设置为 64M

将 semi space 调整为 64M 后,进行线上压测,并且在压测期间获取 CPU Profile 和 GC Trace,如下图所示:

可以看到 garbage collector 阶段 CPU 耗费占比下降到 7% 左右,再观察下 GC 追踪结果:

显然,semi space 调大为 64M 后,scavenge 次数从近 1000 次降低到 294 次,但是这种状况下每次的 scavenge 回收耗时没有明显增加,还是在 50 ~ 60ms 之间波动,因此 3min 的 GC 追踪总的停顿时间从 48s 下降到 12s,相对应的,业务的 QPS 提升了约 10% 左右。

## II. semi space 设置为 128M

进一步调大 semi space 的值为 128M 时,观察 CPU Profile 结果:

此时 garbage collector 耗费下降相比上面的设置为 64M 并不是很明显,同样观察 GC 追踪结果:

很明显,造成相比设置为 64M 时 GC 占比提升不大的原因是:虽然此时进一步调大了 semi space 至 128M,并且 scavenge 回收的次数从 294 次下降到 145 次,但是每次算法回收耗时近乎翻倍了,因此总收益并不明显。

## III. semi space 设置为 256M

进一步将 semi space 调整为 256M 后测试,结果其实和 128M 时非常类似:相对 64M 的情况,此时 3min 内 scavenge 次数从 294 次下降到 72 次,但是相对的每次算法回收耗时波动到了 150ms 左右,因此整体性能并没有显著提升,入下图所示:

## IV. 小结

通过以上的测试改进 semi space 的值后,可以看到从默认的 16M 设置到 64M 时,Node 应用的整体 GC 性能是有显著提升的,并且反映到压测 QPS 上大约提升了 10%;但是进一步将 semi space 增大到 128M 和 256M 时,收益确并不明显,而且 semi space 本身也是作用于新生代对象快速内存分配,本身不宜设置的过大,因此这次优化最终选取对此项目最优的运行时 semi space 的值为 64M。

# 写在最后

通过 GC 方面的运行时调优来提升我们的项目性能是一种大家不那么常用的方式,这也有很大一部分原因是应用运行时 GC 状态本身不直接暴露给开发者。通过上面这个客户案例,我们可以看到借助于 Node.js 性能平台,实时感知 Node 应用 GC 状态以及进行对应的优化,使得不改一行代码提升项目性能变成了一件非常容易的事情。

原文链接:http://zhuanlan.zhihu.com/p/47425089

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-43432.html

文章标题:Node 案发现场揭秘 如何利用 GC 日志不修改代码调优应用性能

相关文章
Node.js学习(1)----HTTP服务器与客户端
Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端。http.Server 是一个基于事件的 HTTP 服务器,它的核心由 Node.js 下层 C++部分实现,而接口由 Jav...
2015-11-12
如何为高负载网络优化Nginx 和 Node.js?
译者:AlfredCheung 在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对。他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以获得很高的并发,不过,...
2015-11-12
JavaScript短路原理精简代码
js中||和&&的特性帮我们精简了代码的同时,也带来了代码可读性的降低,虽然高效,但请灵活使用。 在js逻辑运算中,0、""、null、false、undefined、NaN都会判为false,其他都为t...
2015-11-12
ASP.NET 2.0 AJAX应用程序设计
ASP.NET Aiax技术是一种实现异步(Asynchronous)网络应用的技术,它被整合在ASP.NET 2.0之中,是As P.NET的一种扩展技术。通过ASENETAjax技术,开发人员或程序员可以将Web服务器控件和客户端脚本结...
2015-11-14
React Native 用JavaScript编写原生ios应用
ReactNative 可以基于目前大热的开源JavaScript库React.js来开发iOS和Android原生App。而且React Native已经用于生产环境Facebook Groups iOS 应用就是基于它开发的。 Re...
2015-11-12
javaScript+turn.js实现图书翻页效果实例代码
为了实现图书翻页的效果我们在网上可以看到很多教程在这里推荐turn.js网上的turn.js 有api不过是英文的 很多人看起来不方便.关于代码也是奇形怪状在这里我将详细讲解如何使用turn.js实现翻页效果,本篇文章只是讲解 ...
2017-03-16
如何编写干净高效的CSS代码
其实CSS的学习并不困难,但在一些较为大型的项目中就显得杂乱无章,变得很难管理,尤其是不同的人编写CSS的风格总会略有不同,从团队合作的层面上来说,就更加难以沟通,所以,我们为此总结了一些如何实现高效整洁的CSS代码原则: 使用Reset但...
2015-11-12
从 Node.js 分裂出 Io.js 事件看开源软件谁做主
Node.js 作为服务器编程语言的后起之秀,常用来构建和运行 Web 应用,近日却爆出其社区出现分裂。由于对官方运营商 Joyent 公司在 Node.js 管理上的长期不满,多位核心开发者另立门户,创建了分支 Io.js。从 GitHu...
2015-11-12
Node.js的不足之处
跨平台编程能力不够强大 Bowery团队指出Go能很方便地在不同系统里进行程序编译,这是他们转入Go的重要原因之一。 作为开发平台,对Linux,Windows,OSX等常见操作系统提供支援是能否吸引开发者的基本要素。在Go中,开发者可以针...
2015-11-12
网站变灰代码
html { filter: grayscale(100%);//IE浏览器 -webkit-filter: grayscale(100%);//谷歌浏览器 -moz-filter: g...
2015-11-12
回到顶部