关于node.js:node性能指标一内存分析与管理

3次阅读

共计 2984 个字符,预计需要花费 8 分钟才能阅读完成。

对于 node 的前言

JavaScript 运行在浏览器的沙盒中,他始终会受限于浏览器的中间层提供的能力。Node 技术的呈现给前端工作关上了新的场面。毫无疑问,古代的前端工程化曾经离不开 Node 的利用了,而 Node 自身的设计是用作服务端语言,越来越多的前端团队,不再只将 node 局限于工程化利用,也开始去负责 BFF 层,比方 SSR 架构、数据适配、数据拼接裁剪、后端利用等。当作为服务端利用的时候,服务的【稳固】与【平安】是最重要的指标,提起性能指标

“首屏加载时长”、“可交互时长”等,这些每一个前端 er 都理解的 h5 性能指标。node 用作服务端,有哪些性能指标是值得咱们留神的呢?

影响 node 服务的因素

node 用作服务端,相比拟前端工程而言,咱们须要关注的不仅仅是 node 本身的个性之外,还有依赖的服务器资源;如果依赖的服务器性能不好,node 服务的性能必然也受到影响;

因而,咱们去思考 node 服务的性能问题时候,须要从两个大的方面去思考:一是 node 运行时会呈现的问题,二是服务器资源的性能

  • CPU
  • 内存
  • 磁盘 I /O
  • 网络 I /O

本文次要剖析内存指标,以及内存透露的隐患排查

内存的限度

node 的贮存分为堆和栈,栈中存储根本数据类型,堆中寄存援用类型:对象与变量;对于 node 存储来说,堆内存是整个内存的次要占用。咱们所关注的内存指标就是指堆内存的占用指标

个别的后端语言简直没有内存限度的问题。然而 node 是基于 V8 引擎,在对象调配上听从 V8 的形式,node 通过 Javascript 应用内存是有限度的,在 64 位零碎最大内存为 1.4G 左右,32 位零碎为 0.7G 左右;之所以有内存的限度,一方面 V8 的设计之初是用于浏览器应用,这个限度的值对于个别网页来说是足够的。更深层的起因是 V8 的垃圾回收机制;

当咱们申明一个变量并赋值的时候,就会寄存在 V8 申请的堆内存中,当堆内存不够会持续申请内存,晓得达到内存的限度。如果超出限度,那么就会呈现内存透露的景象,呈现卡顿等景象;这里的内存指标是最不便去量化的,通过 node 提供 process.memoryUsage() 即可查看与理解

  • rss:过程占用的内存总量。
  • heapTotal:堆内存申请的总量。

<!—->

  • heapUsed:理论堆内存使用量。

\

垃圾回收

V8 垃圾回收的根底是先将内存进行分代;在 V8 中依照对象存活的工夫将内存的进行分代。存活工夫短(可立刻回收的变量)的放入新生代,常驻内存(全局变量、无奈立刻去回收的变量)放入老生代;

v8 内存空间 = 新生代占用内存空间 + 老生代占用内存空间;

node 也提供了扩宽内存的办法,在启动 node 的时候,能够通过传递 –max-old-space-size 和 –max-old-space-size 来调整内存的大小,这两个对应裁减的值就是下面提到的老生代内存与新生代的内存值,这个调整一旦启动,就不可更改,除非再次启动。在 V8 内存受限制的时候,能够依照这个值进行放宽

node --max-old-space-size=1800 server.js // 1800Mb

即便有调整,咱们也不能全部都是用 V8 申请的内存,这源于 v8 的回收策略

目前的 Node 应用的是 scavenge 算法,它基于复制的形式实现垃圾回收,这在肯定的水平是有对内存资源的节约存在;代码开发过程中,也能够按需应用 global.gc() 去被动触发垃圾回收,如果被动触发之后,查问 heapUsed 并没有降落,能够思考是内存透露的存在了

内存透露的剖析

通过上述,如果堆内存达到了堆内存的指标,无奈再为新的变量 / 对象进行申请新内存的时候就是呈现内存透露的景象了。老生代的常驻内存是不会被 V8 回收的,即便是手动登程。代码中常见的几项不会被垃圾立刻回收,积攒过多会造成内存透露隐患:

  • 全局变量援用
  • 闭包作用域内变量

<!—->

  • 模块的缓存

一个内存透露的简略案例,仅供学习内存剖析:每次申请的时候会通过 request 传过来的的信息去数据库取数据,对读取的数据做了一层缓存,简略的示例代码如下:

const {json} = require('express');
const express = require('express');
const {v4: uuid} = require('uuid');

const app = express();


function getDataBase() {const cache = {}
    return function(key) {if (cache[key]) return cache[key]
        let data = new Array(10000).fill('cache')
        cache[key] = data
        return data
    }
    
}

const dataBase = getDataBase()
app.get('/memoryUsage', (req, res, next) => {let uid = uuid()
    let data  = dataBase(uid)
    res.json({
        msg: '内存数据',
        data: JSON.stringify({data})
    })
})
const port = 3100
app.listen(port, () => {console.log(`Example app listening at http://localhost:${port}`)
})

通过 wrk 压测工具压测,你会发现申请数量一多,申请就挂掉了。

这个时候就到了剖析 node 内存的时候了,以下是 Chrome-Memory 剖析

node.js 调试工具:Chrome 调试

  1. 启动 Chrome 开发者工具:启动 node 服务的时候传递--inspect

node --inspect server.js

  1. 关上 chrome, 地址栏输出chrome://inspect, 界面如下图,点击 Target 种的 node 服务,在弹出的弹框中抉择Allocation sampling,点击 start 按钮即开始记录

  1. 如果是单个的申请,看不出什么问题。所有的问题都是在申请量增长的状况下,应用压测工具向 node 服务收回并发申请,我这里应用的是 wrk 工具,先模仿高并发申请

wrk -t12 -c1000 -d30s http://localhost:3100/memoryUsage

发送之前的内存状况:

发送之后 10S 左右,内存就到了 700 多,抉择了 stop

完结录制后,会有录制报告如下图,能够看出 99% 的内存占用全在缓存的代码中,由此能够剖析进去内存隐患的代码

更多的 node 调试,能够参阅:https://www.ruanyifeng.com/bl…

内存监控的理论利用

一个欠缺 node 服务的性能指标不仅仅只有内存这一项,还包含 cpu 利用率、相应工夫、状态码监控等。这些线上的服务,社区内也有很多好用的工具,举荐一个非常简单好用的监控工具 express-status-monitor, 这个工具引入到工程后,通过默认路由(/status) 或者指定的路由既能够拜访各项指标的实时监控

const statusMonitor = require('express-status-monitor')({
  title: 'XXX 服务实时监控',
  spans: [
    {
      interval: 1,           // Every 15 seconds
      retention: 100          // 在内存中保留 60 个数据点
    }
  ]
});

app.use(statusMonitor)

正文完
 0