Sign in
Sign up
Explore
Enterprise
Education
Search
Help
Terms of use
About Us
Explore
Enterprise
Education
Gitee Premium
Gitee AI
AI teammates
Sign in
Sign up
Fetch the repository succeeded.
Donate
Please sign in before you donate.
Cancel
Sign in
Scan WeChat QR to Pay
Cancel
Complete
Prompt
Switch to Alipay.
OK
Cancel
Watch
Unwatch
Watching
Releases Only
Ignoring
3
Star
47
Fork
21
DreamCoders
/
CoderGuide
Code
Issues
1169
Pull Requests
0
Wiki
Insights
Pipelines
Service
JavaDoc
PHPDoc
Quality Analysis
Jenkins for Gitee
Tencent CloudBase
Tencent Cloud Serverless
悬镜安全
Aliyun SAE
Codeblitz
SBOM
Don’t show this again
Update failed. Please try again later!
Remove this flag
Content Risk Flag
This task is identified by
as the content contains sensitive information such as code security bugs, privacy leaks, etc., so it is only accessible to contributors of this repository.
Node性能如何进行监控以及优化?
Backlog
#IAG9KP
陌生人
owner
Opened this issue
2024-07-29 16:04
<h3>一、 是什么</h3><p><code>Node</code>作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下:</p><ul><li>CPU</li><li>内存</li><li>I/O</li><li>网络</li></ul><h4>CPU</h4><p>主要分成了两部分:</p><ul><li>CPU负载:在某个时间段内,占用以及等待CPU的进程总数</li><li>CPU使用率:CPU时间占用状况,等于 1 - 空闲CPU时间(idle time) / CPU总时间</li></ul><p>这两个指标都是用来评估系统当前CPU的繁忙程度的量化指标</p><p><code>Node</code>应用一般不会消耗很多的<code>CPU</code>,如果<code>CPU</code>占用率高,则表明应用存在很多同步操作,导致异步任务回调被阻塞</p><h4>内存指标</h4><p>内存是一个非常容易量化的指标。 内存占用率是评判一个系统的内存瓶颈的常见指标。 对于Node来说,内部内存堆栈的使用状态也是一个可以量化的指标</p><pre><code class="language-js">// /app/lib/memory.js const os = require('os'); // 获取当前Node内存堆栈情况 const { rss, heapUsed, heapTotal } = process.memoryUsage(); // 获取系统空闲内存 const sysFree = os.freemem(); // 获取系统总内存 const sysTotal = os.totalmem(); module.exports = { memory: () => { return { sys: 1 - sysFree / sysTotal, // 系统内存占用率 heap: heapUsed / headTotal, // Node堆内存占用率 node: rss / sysTotal, // Node占用系统内存的比例 } } }</code></pre><ul><li>rss:表示node进程占用的内存总量。</li><li>heapTotal:表示堆内存的总量。</li><li>heapUsed:实际堆内存的使用量。</li><li>external :外部程序的内存使用量,包含Node核心的C++程序的内存使用量</li></ul><p>在<code>Node</code>中,一个进程的最大内存容量为1.5GB。因此我们需要减少内存泄露</p><h4>磁盘 I/O</h4><p>硬盘的<code>IO</code> 开销是非常昂贵的,硬盘 IO 花费的 CPU 时钟周期是内存的 164000 倍</p><p>内存 <code>IO</code>比磁盘<code>IO</code> 快非常多,所以使用内存缓存数据是有效的优化方法。常用的工具如 <code>redis</code>、<code>memcached</code>等</p><p>并不是所有数据都需要缓存,访问频率高,生成代价比较高的才考虑是否缓存,也就是说影响你性能瓶颈的考虑去缓存,并且而且缓存还有缓存雪崩、缓存穿透等问题要解决</p><h3>二、如何监控</h3><p>关于性能方面的监控,一般情况都需要借助工具来实现</p><p>这里采用<code>Easy-Monitor 2.0</code>,其是轻量级的 <code>Node.js</code> 项目内核性能监控 + 分析工具,在默认模式下,只需要在项目入口文件 <code>require</code> 一次,无需改动任何业务代码即可开启内核级别的性能监控分析</p><p>使用方法如下:</p><p>在你的项目入口文件中按照如下方式引入,当然请传入你的项目名称:</p><pre><code class="language-js">const easyMonitor = require('easy-monitor'); easyMonitor('你的项目名称');</code></pre><p>打开你的浏览器,访问 <code>http://localhost:12333</code> ,即可看到进程界面</p><p>关于定制化开发、通用配置项以及如何动态更新配置项详见官方文档</p><h3>三、如何优化</h3><p>关于<code>Node</code>的性能优化的方式有:</p><ul><li>使用最新版本Node.js</li><li>正确使用流 Stream</li><li>代码层面优化</li><li>内存管理优化</li></ul><h3>使用最新版本Node.js</h3><p>每个版本的性能提升主要来自于两个方面:</p><ul><li>V8 的版本更新</li><li>Node.js 内部代码的更新优化</li></ul><h4>正确使用流 Stream</h4><p>在<code>Node</code>中,很多对象都实现了流,对于一个大文件可以通过流的形式发送,不需要将其完全读入内存</p><pre><code class="language-js">const http = require('http'); const fs = require('fs'); // bad http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', function (err, data) { res.end(data); }); }); // good http.createServer(function (req, res) { const stream = fs.createReadStream(__dirname + '/data.txt'); stream.pipe(res); });</code></pre><h4>代码层面优化</h4><p>合并查询,将多次查询合并一次,减少数据库的查询次数</p><pre><code class="language-js">// bad for user_id in userIds let account = user_account.findOne(user_id) // good const user_account_map = {} // 注意这个对象将会消耗大量内存。 user_account.find(user_id in user_ids).forEach(account){ user_account_map[account.user_id] = account } for user_id in userIds var account = user_account_map[user_id]</code></pre><h4>内存管理优化</h4><p>在 V8 中,主要将内存分为新生代和老生代两代:</p><ul><li>新生代:对象的存活时间较短。新生对象或只经过一次垃圾回收的对象</li><li>老生代:对象存活时间较长。经历过一次或多次垃圾回收的对象</li></ul><p>若新生代内存空间不够,直接分配到老生代</p><p>通过减少内存占用,可以提高服务器的性能。如果有内存泄露,也会导致大量的对象存储到老生代中,服务器性能会大大降低</p><p>如下面情况:</p><pre><code class="language-js">const buffer = fs.readFileSync(__dirname + '/source/index.htm'); app.use( mount('/', async (ctx) => { ctx.status = 200; ctx.type = 'html'; ctx.body = buffer; leak.push(fs.readFileSync(__dirname + '/source/index.htm')); }) ); const leak = [];</code></pre><p><code>leak</code>的内存非常大,造成内存泄露,应当避免这样的操作,通过减少内存使用,是提高服务性能的手段之一</p><p>而节省内存最好的方式是使用池,其将频用、可复用对象存储起来,减少创建和销毁操作</p><p>例如有个图片请求接口,每次请求,都需要用到类。若每次都需要重新new这些类,并不是很合适,在大量请求时,频繁创建和销毁这些类,造成内存抖动</p><p>使用对象池的机制,对这种频繁需要创建和销毁的对象保存在一个对象池中。每次用到该对象时,就取对象池空闲的对象,并对它进行初始化操作,从而提高框架的性能</p>
<h3>一、 是什么</h3><p><code>Node</code>作为一门服务端语言,性能方面尤为重要,其衡量指标一般有如下:</p><ul><li>CPU</li><li>内存</li><li>I/O</li><li>网络</li></ul><h4>CPU</h4><p>主要分成了两部分:</p><ul><li>CPU负载:在某个时间段内,占用以及等待CPU的进程总数</li><li>CPU使用率:CPU时间占用状况,等于 1 - 空闲CPU时间(idle time) / CPU总时间</li></ul><p>这两个指标都是用来评估系统当前CPU的繁忙程度的量化指标</p><p><code>Node</code>应用一般不会消耗很多的<code>CPU</code>,如果<code>CPU</code>占用率高,则表明应用存在很多同步操作,导致异步任务回调被阻塞</p><h4>内存指标</h4><p>内存是一个非常容易量化的指标。 内存占用率是评判一个系统的内存瓶颈的常见指标。 对于Node来说,内部内存堆栈的使用状态也是一个可以量化的指标</p><pre><code class="language-js">// /app/lib/memory.js const os = require('os'); // 获取当前Node内存堆栈情况 const { rss, heapUsed, heapTotal } = process.memoryUsage(); // 获取系统空闲内存 const sysFree = os.freemem(); // 获取系统总内存 const sysTotal = os.totalmem(); module.exports = { memory: () => { return { sys: 1 - sysFree / sysTotal, // 系统内存占用率 heap: heapUsed / headTotal, // Node堆内存占用率 node: rss / sysTotal, // Node占用系统内存的比例 } } }</code></pre><ul><li>rss:表示node进程占用的内存总量。</li><li>heapTotal:表示堆内存的总量。</li><li>heapUsed:实际堆内存的使用量。</li><li>external :外部程序的内存使用量,包含Node核心的C++程序的内存使用量</li></ul><p>在<code>Node</code>中,一个进程的最大内存容量为1.5GB。因此我们需要减少内存泄露</p><h4>磁盘 I/O</h4><p>硬盘的<code>IO</code> 开销是非常昂贵的,硬盘 IO 花费的 CPU 时钟周期是内存的 164000 倍</p><p>内存 <code>IO</code>比磁盘<code>IO</code> 快非常多,所以使用内存缓存数据是有效的优化方法。常用的工具如 <code>redis</code>、<code>memcached</code>等</p><p>并不是所有数据都需要缓存,访问频率高,生成代价比较高的才考虑是否缓存,也就是说影响你性能瓶颈的考虑去缓存,并且而且缓存还有缓存雪崩、缓存穿透等问题要解决</p><h3>二、如何监控</h3><p>关于性能方面的监控,一般情况都需要借助工具来实现</p><p>这里采用<code>Easy-Monitor 2.0</code>,其是轻量级的 <code>Node.js</code> 项目内核性能监控 + 分析工具,在默认模式下,只需要在项目入口文件 <code>require</code> 一次,无需改动任何业务代码即可开启内核级别的性能监控分析</p><p>使用方法如下:</p><p>在你的项目入口文件中按照如下方式引入,当然请传入你的项目名称:</p><pre><code class="language-js">const easyMonitor = require('easy-monitor'); easyMonitor('你的项目名称');</code></pre><p>打开你的浏览器,访问 <code>http://localhost:12333</code> ,即可看到进程界面</p><p>关于定制化开发、通用配置项以及如何动态更新配置项详见官方文档</p><h3>三、如何优化</h3><p>关于<code>Node</code>的性能优化的方式有:</p><ul><li>使用最新版本Node.js</li><li>正确使用流 Stream</li><li>代码层面优化</li><li>内存管理优化</li></ul><h3>使用最新版本Node.js</h3><p>每个版本的性能提升主要来自于两个方面:</p><ul><li>V8 的版本更新</li><li>Node.js 内部代码的更新优化</li></ul><h4>正确使用流 Stream</h4><p>在<code>Node</code>中,很多对象都实现了流,对于一个大文件可以通过流的形式发送,不需要将其完全读入内存</p><pre><code class="language-js">const http = require('http'); const fs = require('fs'); // bad http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', function (err, data) { res.end(data); }); }); // good http.createServer(function (req, res) { const stream = fs.createReadStream(__dirname + '/data.txt'); stream.pipe(res); });</code></pre><h4>代码层面优化</h4><p>合并查询,将多次查询合并一次,减少数据库的查询次数</p><pre><code class="language-js">// bad for user_id in userIds let account = user_account.findOne(user_id) // good const user_account_map = {} // 注意这个对象将会消耗大量内存。 user_account.find(user_id in user_ids).forEach(account){ user_account_map[account.user_id] = account } for user_id in userIds var account = user_account_map[user_id]</code></pre><h4>内存管理优化</h4><p>在 V8 中,主要将内存分为新生代和老生代两代:</p><ul><li>新生代:对象的存活时间较短。新生对象或只经过一次垃圾回收的对象</li><li>老生代:对象存活时间较长。经历过一次或多次垃圾回收的对象</li></ul><p>若新生代内存空间不够,直接分配到老生代</p><p>通过减少内存占用,可以提高服务器的性能。如果有内存泄露,也会导致大量的对象存储到老生代中,服务器性能会大大降低</p><p>如下面情况:</p><pre><code class="language-js">const buffer = fs.readFileSync(__dirname + '/source/index.htm'); app.use( mount('/', async (ctx) => { ctx.status = 200; ctx.type = 'html'; ctx.body = buffer; leak.push(fs.readFileSync(__dirname + '/source/index.htm')); }) ); const leak = [];</code></pre><p><code>leak</code>的内存非常大,造成内存泄露,应当避免这样的操作,通过减少内存使用,是提高服务性能的手段之一</p><p>而节省内存最好的方式是使用池,其将频用、可复用对象存储起来,减少创建和销毁操作</p><p>例如有个图片请求接口,每次请求,都需要用到类。若每次都需要重新new这些类,并不是很合适,在大量请求时,频繁创建和销毁这些类,造成内存抖动</p><p>使用对象池的机制,对这种频繁需要创建和销毁的对象保存在一个对象池中。每次用到该对象时,就取对象池空闲的对象,并对它进行初始化操作,从而提高框架的性能</p>
Comments (
0
)
Sign in
to comment
Status
Backlog
Backlog
Doing
Done
Closed
Assignees
Not set
Labels
Node
Not set
Label settings
Milestones
No related milestones
No related milestones
Pull Requests
None yet
None yet
Successfully merging a pull request will close this issue.
Branches
No related branch
No related branch
master
Planed to start   -   Planed to end
-
Top level
Not Top
Top Level: High
Top Level: Medium
Top Level: Low
Priority
Not specified
Serious
Main
Secondary
Unimportant
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
Going to Help Center
Search
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
Comment
Repository Report
Back to the top
Login prompt
This operation requires login to the code cloud account. Please log in before operating.
Go to login
No account. Register