NodeJS 程序CPU占用过高

简介: NodeJS 程序CPU占用过高

服务部署场景

采用 Docker Swarm 部署,三个应用节点。


产生场景

在一个阴沉的天气里,突然客户说系统登录慢,页面数据响应也慢,打开 VMWareESXi 系统的管理界面,查看数据服务器和应用服务器的状态,发现数据服务运行正常,但是监控服务器就接近崩溃了,如下所示:

应用服务器监控.png


问题定位

首先登录任意一个节点服务器,通过 top 命令来查看系统状态。得到结果如下图所示:

应用服务器资源占用数据.png

基本可以发现是 node 导致的了。接下来开始分析为什么导致了 CPU 占用过高。


服务状态记录

在启动 node 服务的时候加上 --prof 参数,如下所示:

$ node --prof dist/main.js点击复制复制失败已复制


这样就会在项目根目录下生成一个日志文件,格式为: isolate-0XXXXXXXXXXX-v8-XXXX.log


运行一段时间后将这个文件拿到,但是这个文件是不能直接看的,看不懂,可以打开看一下里面的内容大致如下:

v8-version,8,4,371,19,-node.17,0
shared-library,/usr/local/bin/node,0x555cadf79000,0x555cafa23000,0
shared-library,/usr/local/bin/node,0x555cadf79000,0x555cafb7a000,0
shared-library,/usr/lib/libgcc_s.so.1,0x7f430f948000,0x7f430f957000,0
shared-library,/usr/lib/libstdc++.so.6.0.28,0x7f430f95c000,0x7f430fa9e000,0
shared-library,/lib/ld-musl-x86_64.so.1,0x7f430faf5000,0x7f430fb51000,0
shared-library,[vdso],0x7ffce57da000,0x7ffce57db000,0
profiler,begin,1000
tick,0x7f430fb48885,2952,0,0x0,6
tick,0x555caee02588,2991,0,0x0,6
tick,0x555caeef89f0,4525,0,0x0,6
tick,0x555caee025f0,5161,0,0x0,6
tick,0x555caec558e6,6314,0,0x0,6
tick,0x7f430fb29c4d,7410,0,0x0,6
code-creation,Builtin,3,7514,0x555caf0ef4c0,1632,RecordWrite
code-creation,Builtin,3,7551,0x555caf0efb40,424,EphemeronKeyBarrier
code-creation,Builtin,3,7566,0x555caf0efd00,44,AdaptorWithBuiltinExitFrame
code-creation,Builtin,3,7582,0x555caf0efd40,291,ArgumentsAdaptorTrampoline
code-creation,Builtin,3,7597,0x555caf0efe80,207,CallFunction_ReceiverIsNullOrUndefined
code-creation,Builtin,3,7622,0x555caf0eff60,260,CallFunction_ReceiverIsNotNullOrUndefined
code-creation,Builtin,3,7632,0x555caf0f0080,289,CallFunction_ReceiverIsAny
code-creation,Builtin,3,7640,0x555caf0f01c0,127,CallBoundFunction
code-creation,Builtin,3,7648,0x555caf0f0240,109,Call_ReceiverIsNullOrUndefined
code-creation,Builtin,3,7656,0x555caf0f02c0,109,Call_ReceiverIsNotNullOrUndefined
code-creation,Builtin,3,7665,0x555caf0f0340,109,Call_ReceiverIsAny
code-creation,Builtin,3,7673,0x555caf0f03c0,866,CallProxy
code-creation,Builtin,3,7680,0x555caf0f0740,75,CallVarargs
code-creation,Builtin,3,7687,0x555caf0f07a0,1056,CallWithSpread
code-creation,Builtin,3,7695,0x555caf0f0be0,926,CallWithArrayLike点击复制复制失败已复制

我们需要将其转换成可以看得懂的,有两种方案,一种是 火焰图 ,还有一种是 node 自带的 profile 功能。


火焰图

首先介绍火焰图方式,这个由于可视化,所以比较好看。

$ npm install -g flamebearer    # 全局安装flamebearer包
$ node --prof-process --preprocess -j isolate*.log | flamebearer    # 使用flamebearer包生成火焰图点击复制复制失败已复制

之后就能得到一个 flamegraph.html 文件,通过浏览器打开即可看到火焰图信息。


profile文件

通过node自带的分析诊断功能,得到log日志。

$ node --prof-process isolate*.log > process.txt点击复制复制失败已复制


以上命令能够生成process.txt日志文件,打开后内容大致如下:

Statistical profiling result from isolate-0x555cb25a7d60-1-v8.log, (61102 ticks, 81 unaccounted, 0 excluded).
 [Shared libraries]:
   ticks  total  nonlib   name
  41793   68.4%          /usr/local/bin/node
  10715   17.5%          /lib/ld-musl-x86_64.so.1
    173    0.3%          /usr/lib/libstdc++.so.6.0.28
     14    0.0%          [vdso]
 [JavaScript]:
   ticks  total  nonlib   name
   2221    3.6%   26.4%  LazyCompile: *RawSqlResultsToEntityTransformer.transformRawResultsGroup /app/node_modules/typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js:76:84
   1281    2.1%   15.2%  LazyCompile: *PostgresDriver.prepareHydratedValue /app/node_modules/typeorm/driver/postgres/PostgresDriver.js:494:62
    877    1.4%   10.4%  LazyCompile: *handlePacket /app/node_modules/pg-protocol/dist/parser.js:93:17
    727    1.2%    8.6%  LazyCompile: *string /app/node_modules/pg-protocol/dist/buffer-reader.js:30:11
    611    1.0%    7.3%  LazyCompile: *handleDataRow /app/node_modules/pg/lib/query.js:79:16
    478    0.8%    5.7%  RegExp: (\d{1,})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})(\.\d{1,})?.*?( BC)?$
    364    0.6%    4.3%  LazyCompile: *parseDate /app/node_modules/postgres-date/index.js:8:37
    246    0.4%    2.9%  LazyCompile: *parse /app/node_modules/pg-protocol/dist/parser.js:28:10
    184    0.3%    2.2%  RegExp: ([Z+-])(\d{2})?:?(\d{2})?:?(\d{2})?
    163    0.3%    1.9%  LazyCompile: *slice buffer.js:608:12
……点击复制复制失败已复制


问题分析

我更喜欢这两个结合起来看,火焰图直观, profile 文件详细。


不管是火焰图还是 profile 文件,里面的内容大部分都是包或者底层的信息。现实场景中大概率都是我们手写的代码导致的(当然也可能有包的原因,我还真遇到过,后面讲如何分析包原因导致的问题方法)。那么我们可以很容易的进行筛选。本案例以 nestjs 后台服务运行信息为讲解数据源。


文件下载:

process.txt

flamegraph.html


我们的后台服务因为有开发规范,文件命名并不是随意的,都会带有标识,比如: xxx.controller.tsxxx.service.tsxxx.util.ts


架构规范流程如下:

微信截图_20221207205607.png


所以大概率出现问题的部分就是 service 文件。那么在分析火焰图和 profile 文件的时候,就可以通过 搜索 来辅助定位,最开始搜索 services 关键字,很明显就能找到问题所在。

profile问题定位.png


文件下载:alarm.crontab.service.js

可以很明显的看到是 /app/dist/modules/alarm/services/alarm.crontab.service.js 文件在 5925 列这个匿名方法占用了大量的 CPU 资源。打开这段代码如下:

bug点.png


可以很明显的发现是从数据流式取出数据并进行逻辑处理这里出现了问题。很大概率就是这里拿到的数据量过大,并发处理导致 node 频繁 GC ,导致 CPU 占用过高。接下来搞个节流+休息就OK了。问题修复完成!


底层包导致

上述场景确实是我们写的代码导致的,但是有的时候会发现基本上 CPU 占用都没有和自己编写的代码相关的信息。下面是一个底层包 bug 导致的火焰图文件:

flamegraph.html


经过观察,发现全部是 mongodb 连接那里占用的资源,占用了 94.92% 的资源。但是以前是没有这个问题的,查看 npm 上相应驱动库 mongoose 的版本为 5.11.19 ,以前的版本是 5.10.x ,抱着尝试的态度,将版本切换到 5.10.x 后居然解决了这个问题。因此得出结论为 npm 包的 bug

目录
相关文章
|
6月前
|
JavaScript 前端开发 Serverless
函数计算只支持Node.js,我用C++写的程序怎么运行?
函数计算只支持Node.js,我用C++写的程序怎么运行?
112 1
|
存储 JavaScript NoSQL
使用Node.js构建强大的后端应用程序
Node.js是一个基于Chrome V8引擎构建的JavaScript运行时环境,它可以帮助开发者构建快速、可扩展和高性能的后端应用程序。在本篇文章中,我们将介绍一些与Node.js相关的技术,让你更好地利用这个强大的工具。
195 0
|
6月前
|
负载均衡 JavaScript 算法
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
156 1
|
3月前
|
JavaScript Java Serverless
函数计算产品使用问题之如何使用Node.js编写程序
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
3月前
|
C++
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
44 0
|
5月前
|
缓存 C语言 计算机视觉
程序与技术分享:CPU0处理器的架构及应用
程序与技术分享:CPU0处理器的架构及应用
|
28天前
|
运维 JavaScript Linux
容器内的Nodejs应用如何获取宿主机的基础信息-系统、内存、cpu、启动时间,以及一个df -h的坑
本文介绍了如何在Docker容器内的Node.js应用中获取宿主机的基础信息,包括系统信息、内存使用情况、磁盘空间和启动时间等。核心思路是将宿主机的根目录挂载到容器,但需注意权限和安全问题。文章还提到了使用`df -P`替代`df -h`以获得一致性输出,避免解析错误。
|
2月前
|
JavaScript 前端开发 Windows
第一个node程序23
第一个node程序23
|
2月前
|
JavaScript Linux 开发工具
如何将nodejs项目程序部署到阿里云服务器上
该文章详细描述了将Node.js项目部署到阿里云服务器的步骤,包括服务器环境配置、项目上传及使用PM2进行服务管理的过程。
|
4月前
|
缓存 弹性计算 数据库
阿里云2核4G服务器支持多少人在线?程序效率、并发数、内存CPU性能、公网带宽多因素
2核4G云服务器支持的在线人数取决于多种因素:应用效率、并发数、内存、CPU、带宽、数据库性能、缓存策略、CDN和OSS使用,以及用户行为和系统优化。阿里云的ECS u1实例2核4G配置,适合轻量级应用,实际并发量需结合具体业务测试。
79 0
阿里云2核4G服务器支持多少人在线?程序效率、并发数、内存CPU性能、公网带宽多因素