如何进行 GC 调优提升 Node 应用性能

简介:

前情

用户项目上线进行压测时,CPU 100% 时单进程 QPS 在 100 上下浮动,想进行一些进一步的优化。经过接入 Node.js 性能平台 后,在压测试做 CPU Profile 观察系统 CPU 耗费在什么地方:
1539930645541-d2a7154b-767e-4be8-aaab-a9
可以看到 _tickDomainCallbackgarbage collector 在 CPU 的占比加起来高达 83%,而经过和用户沟通,发现 _tickDomainCallback 内部的耗费 CPU 高的逻辑分别是 typeorm 和自己的 controller 逻辑,typeorm 方面因为 api 变动的原因不太方便升级,controller 逻辑则是已经优化过了暂时没有提升的空间。
因此很自然的,我们会把进一步提升项目性能的目光放到 GC 阶段。这里在 3min 的 CPU 采样期间,GC 阶段的调用占比高达 27.5%,结合当时的性能平台监控数据,我们可以看到绝大部分都是 scavenge 阶段,此时继续进行线上压测,同时做 GC Trace 来获取更多 GC 阶段的详细信息:
1539932616406-9bfe5886-b0ba-4937-9a74-a4
在 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 的值来进行优化呢?

优化

V8 的代码查看后发现默认的 semi space 的值为 16M(alinode-v3.11.3/node-v8.11.3),经过和用户沟通,我们打算分别调整为 64M128M256M 来进行观察,可以通过在 node 启动应用时加上 --max_semi_space_size 的 flag 来生效。

I. semi space 设置为 64M

将 semi space 调整为 64M 后,进行线上压测,并且在压测期间获取 CPU Profile 和 GC Trace,如下图所示:
1539933362523-cd0f0774-90af-4486-ae1e-bb
可以看到 garbage collector 阶段 CPU 耗费占比下降到 7% 左右,再观察下 GC 追踪结果:
1539933445776-f70fc122-09d5-4824-a897-16
显然,semi space 调大为 64M 后,scavenge 次数从近 1000 次降低到 294 次,但是这种状况下每次的 scavenge 回收耗时没有明显增加,还是在 50 ~ 60ms 之间波动,因此 3min 的 GC 追踪总的停顿时间从 48s 下降到 12s,相对应的,业务的 QPS 提升了约 10% 左右。

II. semi space 设置为 128M

进一步调大 semi space 的值为 128M 时,观察 CPU Profile 结果:
1539933694785-bdc43a54-9873-466a-8cdf-0d
此时 garbage collector 耗费下降相比上面的设置为 64M 并不是很明显,同样观察 GC 追踪结果:
1539933810113-bcc014ff-ea7e-4812-a9cf-08
很明显,造成相比设置为 64M 时 GC 占比提升不大的原因是:虽然此时进一步调大了 semi space 至 128M,并且 scavenge 回收的次数从 294 次下降到 145 次,但是每次算法回收耗时近乎翻倍了,因此总收益并不明显。

III. semi space 设置为 256M

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

IV. 小结

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

尾声

通过 GC 方面的运行时调优来提升我们的项目性能是一种大家不那么常用的方式,这也有很大一部分原因是应用运行时 GC 状态本身不直接暴露给开发者。通过上面这个真实的客户案例,我们可以看到借助于 Node.js 性能平台,实时感知 Node 应用 GC 状态以及进行对应的优化,使得不改一行代码提升项目性能变成了一件非常容易的事情。
相关实践学习
通过性能测试PTS对云服务器ECS进行规格选择与性能压测
本文为您介绍如何利用性能测试PTS对云服务器ECS进行规格选择与性能压测。
目录
相关文章
|
19天前
|
JSON JavaScript 前端开发
❤Nodejs 第九章(token身份认证和express-jwt的安装认识)
【4月更文挑战第9天】Node.js第九章介绍了Token身份认证,特别是JWT(JSON Web Token)作为跨域认证的解决方案。JWT由Header、Payload和Signature三部分组成,用于在客户端和服务器间安全传输用户信息。前端收到JWT后存储在localStorage或sessionStorage中,并在请求头中发送。Express-JWT是一个中间件,用于解析JWT。基本用法包括设置secret和algorithms。注意安全问题,避免混合使用不同算法以防止降级攻击。
38 0
|
1月前
|
JavaScript Windows
Win7内网安装高版本的Node方法,亲测有效node-v16.16.0
Win7内网安装高版本的Node方法,亲测有效node-v16.16.0
60 0
|
2月前
|
JavaScript Linux 数据安全/隐私保护
node内网安装npm私服以及依赖包上传发布verdaccio
node内网安装npm私服以及依赖包上传发布verdaccio
93 1
|
1天前
|
资源调度 jenkins 持续交付
jenkins 自动安装nodejs16.16.0版本报错处理
jenkins 自动安装nodejs16.16.0版本报错处理
|
12天前
|
JavaScript 前端开发 Linux
Node.js安装与配置
`Node.js` 是一个基于 `Chrome V8` 引擎的 `JavaScript` 运行环境,它允许开发者使用 `JavaScript` 编写服务器端代码。以下是 `Node.js` 的安装与配置的详细步骤:
Node.js安装与配置
|
12天前
|
JSON JavaScript 关系型数据库
❤Nodejs 第十六章(Nodejs环境安装和依赖使用)
【4月更文挑战第16天】本文介绍了Node.js环境安装和项目搭建步骤。检查Node.js和npm版本安装核心依赖,如Express(Web应用框架)、MySQL库、CORS(解决跨域问题)、body-parser(解析POST数据)、express-jwt和jsonwebtoken(JWT验证)、multer(文件上传处理)、ws(WebSocket支持),以及可选的dotenv(管理环境变量)和ejs(模板引擎)。完整源码可在Gitee开源项目[nexusapi](https://gitee.com/lintaibai/nexusapi)中找到。
22 0
|
19天前
|
JavaScript Linux Python
Linux 安装 Node.js | NPM
Linux 安装 Node.js | NPM
8 0
|
25天前
node安装常用工具
node安装常用工具
9 0
|
1月前
|
数据采集 JavaScript 前端开发
❤Nodejs 第一章(认识安装)
【4月更文挑战第1天】Nodejs 是一个跨平台的 JavaScript 运行时环境,基于Chrome的V8引擎。它以异步I/O和事件驱动为特点,用于构建高效、可扩展的网络应用。Node.js 使用npm作为包管理工具,拥有大量的模块资源。它适合IO密集型应用,但不适宜CPU密集型任务。其应用场景广泛,包括前端框架、后端服务、爬虫、桌面应用、移动应用、构建工具和CICD流程等。
73 1
❤Nodejs 第一章(认识安装)
|
1月前
|
Linux Windows
教你在Linux上安装Node并用Electron打包deb和rpm包
教你在Linux上安装Node并用Electron打包deb和rpm包
43 9