网站首页 > 基础教程 正文
背景
近期,为了评估服务性能,测试同学对关键业务接口进行了压测,单台NodeJS服务开启3个进程的情况下,QPS最高达320多。为了确认服务是否还有优化空间,我们使用阿里云的 NodeJS性能平台 对服务进行分析,定位了服务的瓶颈,并在阿里云的同学帮助下采取了相应的措施,优化了服务的性能。
问题排查与分析
Step1 获取与分析CPU Profile
当我们以400并发量,对单一业务接口进行压测,发现QPS为320时,服务器CPU被打满。为了找到是什么原因导致CPU达到了性能瓶颈,我们使用了阿里云的「NodeJS性能平台」,抓取了压测时的 CPU Profile 信息。
经过分析,我们发现 _tickDomainCallback 和 garbage collector 在CPU占比很大,其中 _tickDomainCallback占了50%多,GC 也占了27%的比例。通过展开 _tickDomainCallback 里的内容,发现CPU占比高的逻辑主要是TypeORM 和4处业务逻辑。
Step2 排查数据库性能
当我们看到TypeORM时,我们以为是数据库消费不过来(生产与消费能力不匹配,Query队列产生大量堆积),导致TypeORM消耗大量CPU资源。后来,我们进行了第二次压测,并在服务器CPU打满时获取了RDS的性能分析报告。报告显示:
- 数据库CPU使用了15%的资源
- 平均查询响应速度小于15ms
- 无慢查询记录
- 无死锁记录
因此,我们排除了RDS导致TypeORM消耗CPU资源。我们推测可能与TypeORM本身的代码有关,我们使用了一个非常早期的TypeORM版本(v0.0.11)。阿里云的同学推荐我们升级TypeORM的版本试试,看看会不会有所改善。但是最新的TypeORM版本与早期的版本API已经发生了变化,无法进行平滑升级。因此,放弃了对TypeORM优化。
Step3 排查业务逻辑代码
我们将可能影响性能的业务代码进行了Review,发现优化空间并不是很大,代码本身已经经过了精简和优化。无法进行进一步提升,我们将优化重点放在了占比高达27%的 GC 上。
Step4 GC 信息抓取与分析
为了获得详细的GC信息,我们再次进行了压测,并获取了 GC Trace 信息。结果如下图:
从图中,我们可以获取到一些重要信息:
- GC时间占比为26.87%
- 3分钟内,GC暂时时间为47.8s,且scavenge占了大多数
- 平均GC暂停时间为50~60ms
根据这些信息,我们可以得出 scavenge 非常频繁,导致了CPU资源的占用。
scavenge 发生在新生代的内存回收阶段,这个阶段触发条件是, semi space allocation failed(半空间分配失败)。可以推测出,压测期间我们的代码逻辑频繁的生成大量的小对象,导致 semi space很快被分配满,从而导致了 scavenge 回收和CPU资源的占用。既然这样,我们可不可通过调整 semi space(半空间)的大小,减少GC的次数来优化对CPU的占用。
Step5 GC 调优与测试
NodeJS在64位系统上,默认的semi space大小为16M。
我们将 semi space 进行了3次调整,分别设为64M、128M、256M,对不同值情况下的服务进行了压测并获取了对应 GC Trace 和 CPU Profile。
修改 semi space 方法
对于普通node服务:
node index.js --max_semi_space_size=64
对于PM2启动的服务,在pm2的config文件中添加:
node_args: '--max_semi_space_size=64',
1) 64M
将 semi space 修改为64M,并进行线上压测,获取压测时的 GC Trace 和 CPU Profile信息:
对比修改前的数据,我们发现:
- GC的CPU占比从27.5%下降到了7.14%;
- 3分钟内GC次数,从1008次降到了312次。其中,Scavenge的次数从988次下降到了294次;
- GC时间,从原来的47.7s下降到了11.8s
- GC平均暂停时间在40ms左右
GC时间从47.7s下降到了11.8s,相应的,QPS提升了10%。
2) 128M
将 semi space 调整到128M,得到的 GC Trace 和 CPU Profile信息:
对比64M时的数据,我们可以发现:
- 与64M时GC次相比,GC次数从312下降到了145;
- Scavenge算法回收时间,增加了1倍。从平均50ms涨到了100ms;
- Mark-sweep的次数没有发生变化
- CPU占比略微下降,从7.14降到了6.71
可以看出,将 semi space从64M调整到了128M,性能并没有很大的提升。相反,Scavenge算法回收时间几乎增长了一倍。
3) 256M
将 semi space 调整到256M,得到的 GC Trace 和 CPU Profile信息:
可以观察到:
- 与128M时相比,GC次数下降了一倍
- 但是Scavenge回收的时间,波动到了150ms。
- CPU占比,也略微下降了一点,降到了5.99
可以看出,将 semi space调整到了 256M,性能并没有显著提升,且增加了 Scavenge 的回收时间。
小结
将 semi space 从16M调整到64M时,GC的CPU占比从27.5%下降到了7.14%,Scavenge算法平均回收耗时减少,QPS提升了10%。继续调大 semi space,性能并没有显著提升,且Scavenge算法回收时间增加。semi space本身用于新生代对象快速分配,不适合调整过大。因此,semi space 设置为64M较为合适。
总结
通过将semi space调大,触发 Scavenge算法回收的概率降低,GC的次数也随之减少。且 Scavenge算法回收内存的时间也较为合理,因而可以降低GC在CPU中的占比。
本文主要介绍了线上服务的性能瓶颈的排查与GC调优,并没有介绍V8 垃圾回收机制的原理。推荐感兴趣的同学,阅读朴灵老师的《深入浅出Node.js》中关于《V8的垃圾回收机制》一节。其中,详细了介绍了V8用到的各种算法,非常有助于理解性能调优的原理。
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,
,咱们下期见!
答案获取方式:已赞 已评 已关~
猜你喜欢
- 2024-12-23 JavaScript开源良心插件,纯前端网页图片剪裁插件——cropperjs
- 2024-12-23 用友UAP马太航:解析移动开发中响应式布局
- 2024-12-23 openCVjs图像处理之自动矫正 opencv 自动化
- 2024-12-23 Cycling 74 推出 Max 9 交互式编程 软件
- 2024-12-23 qunit/mocha/jest在nodejs下的集成测试原理分析
- 2024-12-23 JS基础与高级应用: 性能优化 css js性能优化
- 2024-12-23 LeetCode 力扣官方题解 | 1614. 括号的最大嵌套深度
- 2024-12-23 一个开源的拟物化设计风格的Vue组件库——qui-max
- 2024-12-23 FStorm Render v1.5.7J for 3dmax2016-2025(3dmax插件)安装教程
- 2024-12-23 兄弟们我忍不住下山了,买了个2022年产的RX580
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)