使用 node.js 的心得

目录

前言

安装 Node.js 和初始化项目:mac/windows安装|卸载node以及用n/nvm管理node版本

一、Node.js 概览

  • 定义:Node.js = 在服务器/桌面环境运行 JavaScript 的运行时。核心由 V8 引擎(执行 JS) + libuv(事件循环与异步 I/O) + Node 的标准库(核心模块)构成。

  • 设计目标:高并发 I/O(非阻塞、事件驱动)、轻量级服务器端开发。

  • 擅长场景:HTTP API、实时通信(WebSocket/Socket.IO)、代理/网关、CLI 工具、构建工具、Electron 桌面应用。

  • 不擅长场景:CPU 密集型任务(长时间阻塞主线程)。

二、关键组件

1、关键组件的运行时架构图

2、JavaScript 单线程运行时(JS Runtime)

Node.js 使用 单线程 执行 JavaScript 代码。

意味着:

  • 代码一个接一个执行(类似浏览器)
  • 不能直接用多线程跑 JavaScript

但 单线程不等于 Node.js 只能处理一个请求,因为它有:

  • 事件循环(调度任务)
  • 线程池(处理重任务)
  • 系统内核(处理网络 I/O)

这就是 Node 高并发的根本原因:不是靠 JS,而是靠事件循环 + libuv。

3、V8 引擎(Chrome 里的那套)

Node.js 的 JS 引擎就是:Chrome 的 V8

功能包括:

  • 解析 JS(Parser)
  • 解释执行(Interpreter)
  • 编译优化(TurboFan)
  • 垃圾回收(GC)

优点:

  • 执行速度极快
  • 内建优化器,适合服务器代码
  • Node 之所以快,就是因为背后是 Google 花巨资优化的 V8。

4、事件循环(Event Loop)------Node 核心中的核心(⭐️)

事件循环是 Node.js 的调度中心。

它负责:

  • 执行 JS 主线程任务
  • 处理异步任务的回调
  • 管理 I/O 完成事件
  • 分配 Timer / Promise / I/O 队列顺序

核心阶段包括:

  • timers(setTimeout/setInterval)
  • pending callbacks
  • idle/prepare
  • poll(I/O)
  • check(setImmediate)
  • close callbacks

理解事件循环 = 理解 Node 性能与异步。

5、事件驱动架构(EventEmitter)

Node 内部所有组件都基于事件机制:

  • fs 文件读写
  • http 请求事件 (req.on('data'))
  • net socket
  • stream 流
  • process 的 exit 事件

你也可以自己写事件:

cpp 复制代码
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('start', msg => console.log(msg));
emitter.emit('start', 'hello');

事件 = Node 处理异步的核心哲学

6、非阻塞 I/O 模型------Node 的杀手级能力(⭐️)

传统后端(Java、PHP、Python):

  • 一次请求 = 一条线程
  • I/O 要等待(阻塞)

Node.js:

  • I/O 交给系统内核或线程池
  • 当 I/O 完成时发事件通知
  • JS 主线程继续跑别的任务

因此:

  • Node 可以轻松处理 几万并发
  • Node 非常适合 I/O 密集(数据库、文件、网络)

7、Libuv(Node 背后的 C++ 引擎)------必须理解(⭐️)

libuv 是 Node.js 底层最重要的组件,它提供:

  • I/O 多路复用(epoll / kqueue)
  • 事件循环的实现
  • 线程池
  • 文件系统封装
  • TCP/UDP 实现

事件循环 ≠ JS 写的

事件循环 = libuv 写的(C++)

libuv 的存在,让 Node 能提供:

  • 非阻塞 I/O
  • 大规模并发
  • 高性能网络

8、线程池(Thread Pool)------文件/压缩/加密 都靠它(⭐️)

Node 虽然是单线程 JS,但底层有一个 线程池(默认 4 个) 处理重任务。

由 libuv 管理,用于:

  • fs.readFile 读取大文件
  • crypto.pbkdf2 密码哈希
  • zlib.gzip 压缩
  • DNS lookup

示例:

cpp 复制代码
const crypto = require('crypto');
crypto.pbkdf2('password', 'salt', 100000, 64, 'sha512', () =>
  console.log('done')
);

CPU 密集任务不会卡死主线程,因为它们跑在线程池里。

9、模块系统(CommonJS, ES Modules)

Node 原生支持两套模块系统:

  • CommonJS(require)------传统、最常用:
cpp 复制代码
const fs = require('fs');
module.exports = {}
  • ESM(import)------现代语法:
cpp 复制代码
import fs from 'fs';
export default {}

Node 现在同时支持两者,但 ESM 正逐渐成为主流。

10、Buffer(处理二进制数据)------大文件/网络必须掌握(⭐️)

Buffer 是 Node.js 专门处理 二进制数据 的结构。

例子:

cpp 复制代码
const buf = Buffer.from('hello');
console.log(buf);

用途:

  • 文件读写
  • 网络传输数据包
  • 图片、音频处理
  • Stream 的底层数据结构

Buffer + Stream 是 Node.js 最底层的两个核心。

11、Stream(流)------Node 最强能力之一(⭐️)

Node 的 Stream 是对大数据量的按"块"处理方式。

四类流:

类型 说明
Readable 可读流(文件读取)
Writable 可写流(文件写入)
Duplex 双工(TCP)
Transform 转换流(gzip)

示例:

cpp 复制代码
fs.createReadStream('./big.file')
  .pipe(fs.createWriteStream('./copy.file'));

优点:

  • 大文件不占内存
  • 更快
  • 可以边读边写

12、网络栈(HTTP / TCP / UDP)

Node 的网络组件都是底层自己实现,而不是依赖 Apache/Nginx。

  • HTTP 服务器
cpp 复制代码
http.createServer((req, res) => {
  res.end('hello');
});
  • TCP 服务器
cpp 复制代码
net.createServer(socket => {});
  • UDP 服务器
cpp 复制代码
dgram.createSocket('udp4');

Node 在网络高并发领域非常强。

13、NPM(Node 包管理生态)

Node 的生态繁荣得益于 NPM:

  • 世界最大开源库仓库
  • 所有 Node 项目都依赖 npm/yarn/pnpm

含义:

  • Node = 运行时
  • npm = 生态系统
  • Node.js 实力的 50% 来自 NPM。

三、Node.js 核心 API(按功能分类)

1、基础平台能力:运行环境 / 事件系统

(1)、process(进程信息、环境变量)✔ 全栈必会

常用功能:

功能 示例
读取环境变量 process.env.NODE_ENV
退出进程 process.exit(1)
获取当前目录 process.cwd()
获取命令行参数 process.argv
CPU 数量 process.cpuUsage()

示例:

cpp 复制代码
console.log(process.env.NODE_ENV);

用途:配置分环境部署、CLI 工具。

(2)、events(事件驱动)✔ Node 核心原理

Node 内部所有模块都基于 EventEmitter,如 HTTP、文件流等。

cpp 复制代码
const { EventEmitter } = require('events');
const emitter = new EventEmitter();

emitter.on('start', () => console.log('started'));
emitter.emit('start');

用途:自定义事件机制、插件系统。

(3)、timers(定时器)

用法 API
定时 setTimeout
轮询 setInterval
立即执行 setImmediate
下一事件循环 process.nextTick()

nextTick 常用于同步代码后立刻执行。

2、文件与目录(后端最常用)

(1)、fs(文件系统)✔ 必会

常用功能:

场景 API
读文件 fs.readFile / fs.readFileSync
写文件 fs.writeFile
追加内容 fs.appendFile
判断文件/目录状态 fs.stat
创建目录 fs.mkdir
删除文件 fs.rm
创建文件流 fs.createReadStream

常用示例:

cpp 复制代码
const fs = require('fs');
fs.readFile('./data.txt', 'utf8', (err, data) => console.log(data));

(2)、path(路径管理)✔ Webpack/Vite 必备

场景 API
拼接路径 path.join
绝对路径 path.resolve
扩展名 path.extname

示例:

cpp 复制代码
const path = require('path');
const p = path.join(__dirname, 'data', 'file.txt');

(3)、os(操作系统信息)

常用:

  • os.cpus()
  • os.totalmem()
  • os.freemem()
  • os.homedir()

3、网络与通信(Node 最强能力)

(1)、http(创建 HTTP 服务器)✔ Express 的底层

示例:

cpp 复制代码
const http = require('http');

http.createServer((req, res) => {
  res.end('Hello');
}).listen(3000);

用途:REST API、微服务。

(2)、https(HTTPS 服务器)

cpp 复制代码
https.createServer({ key, cert }, handler);

用于:部署安全站点。

(3)、net(TCP 服务器)

例如实现 WebSocket、Socket 聊天室:

cpp 复制代码
const net = require('net');
net.createServer(socket => {
  socket.write('hello');
});

用途:底层通信、代理、代理服务器。

(4)、dns(域名解析)

cpp 复制代码
dns.lookup()

dns.resolve4()

用途:网络诊断、服务发现。

(5)、dgram(UDP 消息)

用于:

  • 游戏服务器
  • 视频流
  • 局域网广播

4、子进程与多线程(处理 CPU 密集任务)

(1)、child_process(创建子进程)✔ 生产环境常用

四种方式:

场景 API
执行 shell 命令 exec
执行命令并得到 stream spawn
启动 Node 子脚本 fork
同步执行 execSync

示例:

cpp 复制代码
const { exec } = require('child_process');
exec('ls', (err, stdout) => console.log(stdout));

(2)、worker_threads(多线程)✔ 解决 CPU 密集

例:图片压缩、大计算任务。

(3)、cluster(多核负载均衡)

一行代码让 Node 用满所有 CPU 核心:

cpp 复制代码
cluster.fork();

5、数据流(流式处理)

Node 的二级核心:Stream

常见 Stream 类型:

类型 举例
可读流 文件读取、HTTP Request
可写流 文件写入、HTTP Response
双工流 TCP socket
转换流 gzip 压缩/解压

示例:

cpp 复制代码
fs.createReadStream('./file.txt')
  .pipe(fs.createWriteStream('./copy.txt'));

优点:处理大文件不占内存。

6、压缩/加密/工具类

(1)、zlib(压缩)

常用于 gzip 网站内容:

cpp 复制代码
zlib.createGzip();

(2)、crypto(加密、哈希)✔ 账号系统必用

常用:

cpp 复制代码
crypto.createHash('sha256')

crypto.randomBytes()

crypto.createCipheriv()

示例:

cpp 复制代码
crypto.createHash('sha256').update('password').digest('hex');

7、调试与诊断

  • console(日志)
  • inspector(调试)
  • perf_hooks 性能分析

8、URL、查询参数等网络工具

  • URL(新 API)------Web 兼容

9、最实用的 Node.js API 记忆法(高频 24 个)(⭐️⭐️⭐️⭐️⭐️)

如果你只想记重点,下面这 24 个是最常用的,够开发 90% 项目。

  • 文件/目录
    • fs.readFile
    • fs.writeFile
    • fs.createReadStream
    • fs.createWriteStream
    • fs.stat
    • fs.mkdir
    • path.join
    • path.resolve
  • 网络/通信
    • http.createServer
    • https.createServer
    • net.createServer
    • url.URL
    • dns.lookup
  • 系统
    • process.env
    • process.cwd
    • os.cpus
    • os.homedir
  • 多线程/进程
    • child_process.exec
    • child_process.fork
    • worker_threads.Worker
  • 工具类
    • crypto.createHash
    • zlib.createGzip
  • 事件 & 定时器
    • events.EventEmitter
    • setImmediate
    • process.nextTick

四、一个超简单 Node.js 的示例

1、创建最小 Node.js 服务器

在项目根目录创建 index.js:

cpp 复制代码
// index.js
const express = require('express');
const app = express();
const PORT = 3000;

// 中间件,解析 JSON
app.use(express.json());

// 根路由
app.get('/', (req, res) => {
  res.send('Hello Node.js from 0 to 1!');
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

运行:

bash 复制代码
node index.js

浏览器访问 http://localhost:3000,你会看到:

cpp 复制代码
Hello Node.js from 0 to 1!

这是最小 Node.js 项目✅。

2、添加一个简单 API

比如我们做一个 用户列表 API:

cpp 复制代码
// 模拟数据库
let users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

// 获取用户列表
app.get('/api/users', (req, res) => {
  res.json(users);
});

// 添加新用户
app.post('/api/users', (req, res) => {
  const { name } = req.body;
  const newUser = { id: users.length + 1, name };
  users.push(newUser);
  res.status(201).json(newUser);
});

测试:

bash 复制代码
curl http://localhost:3000/api/users
curl -X POST http://localhost:3000/api/users -H "Content-Type: application/json" -d '{"name":"Charlie"}'

3、添加前端页面

在项目根目录创建 index.html:

cpp 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Node.js Demo</title>
</head>
<body>
  <h1>用户列表</h1>
  <ul id="userList"></ul>

  <input type="text" id="username" placeholder="输入名字">
  <button onclick="addUser()">添加用户</button>

  <script>
    async function fetchUsers() {
      const res = await fetch('/api/users');
      const users = await res.json();
      const list = document.getElementById('userList');
      list.innerHTML = '';
      users.forEach(u => {
        const li = document.createElement('li');
        li.textContent = `${u.id}. ${u.name}`;
        list.appendChild(li);
      });
    }

    async function addUser() {
      const name = document.getElementById('username').value;
      if (!name) return alert('请输入名字');
      await fetch('/api/users', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name })
      });
      document.getElementById('username').value = '';
      fetchUsers();
    }

    fetchUsers();
  </script>
</body>
</html>

修改 index.js 让它能返回这个 HTML 页面:

cpp 复制代码
const path = require('path');

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, 'index.html'));
});

现在访问 http://localhost:3000,你就能看到用户列表和添加用户功能了。

4、目录结构

最终项目结构示例:

cpp 复制代码
my-node-app/
├─ index.js
├─ package.json
├─ package-lock.json
└─ index.html

五、全面升级上面的这个示例

我们就把刚才的最小 Node.js 项目升级为一个 完整的全栈 CRUD 项目,具备以下特点:

  • 后端:Node.js + Express + SQLite 数据库
  • 前端:React + Fetch 调用后端 API
  • 功能:用户管理(增删改查)
  • 自动重启:Nodemon

1、初始化项目

假设你在项目目录 my-node-app:

bash 复制代码
mkdir my-fullstack-app
cd my-fullstack-app
npm init -y

安装后端依赖:

bash 复制代码
npm install express sqlite3 cors
npm install -D nodemon
  • express:后端框架
  • sqlite3:数据库
  • cors:允许前端跨域请求
  • nodemon:开发时自动重启

修改 package.json 增加脚本:

json 复制代码
"scripts": {
  "start": "node index.js",
  "dev": "nodemon index.js"
}

2、搭建后端:Express + SQLite

在根目录创建 index.js:

cpp 复制代码
const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const cors = require('cors');

const app = express();
const PORT = 3000;

app.use(cors());
app.use(express.json());

// 初始化数据库
const db = new sqlite3.Database('./users.db', (err) => {
  if (err) console.error(err.message);
  else console.log('Connected to SQLite database.');
});

// 创建用户表
db.run(`CREATE TABLE IF NOT EXISTS users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL
)`);

// --- CRUD API ---

// 获取用户列表
app.get('/api/users', (req, res) => {
  db.all(`SELECT * FROM users`, [], (err, rows) => {
    if (err) return res.status(500).json({ error: err.message });
    res.json(rows);
  });
});

// 添加用户
app.post('/api/users', (req, res) => {
  const { name } = req.body;
  db.run(`INSERT INTO users(name) VALUES(?)`, [name], function(err) {
    if (err) return res.status(500).json({ error: err.message });
    res.status(201).json({ id: this.lastID, name });
  });
});

// 更新用户
app.put('/api/users/:id', (req, res) => {
  const { id } = req.params;
  const { name } = req.body;
  db.run(`UPDATE users SET name=? WHERE id=?`, [name, id], function(err) {
    if (err) return res.status(500).json({ error: err.message });
    res.json({ id, name });
  });
});

// 删除用户
app.delete('/api/users/:id', (req, res) => {
  const { id } = req.params;
  db.run(`DELETE FROM users WHERE id=?`, [id], function(err) {
    if (err) return res.status(500).json({ error: err.message });
    res.json({ id });
  });
});

// 启动服务器
app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});

到这里,后端已经可以完成完整的 CRUD ✅。

3、搭建前端:React

在根目录创建 React 项目(使用 Vite 更轻量):

bash 复制代码
npm create vite@latest frontend -- --template react
cd frontend
npm install

启动前端:

bash 复制代码
npm run dev

前端默认在 http://localhost:5173

4、前端实现用户管理

修改 frontend/src/App.jsx:

cpp 复制代码
import { useEffect, useState } from 'react';

function App() {
  const [users, setUsers] = useState([]);
  const [name, setName] = useState('');
  const [editId, setEditId] = useState(null);

  const API = 'http://localhost:3000/api/users';

  // 获取用户
  const fetchUsers = async () => {
    const res = await fetch(API);
    const data = await res.json();
    setUsers(data);
  };

  useEffect(() => { fetchUsers(); }, []);

  // 添加或更新用户
  const saveUser = async () => {
    if (!name) return alert('请输入名字');
    if (editId) {
      await fetch(`${API}/${editId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name })
      });
      setEditId(null);
    } else {
      await fetch(API, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name })
      });
    }
    setName('');
    fetchUsers();
  };

  // 删除用户
  const deleteUser = async (id) => {
    await fetch(`${API}/${id}`, { method: 'DELETE' });
    fetchUsers();
  };

  // 编辑用户
  const editUser = (user) => {
    setName(user.name);
    setEditId(user.id);
  };

  return (
    <div style={{ padding: 20 }}>
      <h1>用户管理系统</h1>
      <input 
        value={name} 
        onChange={e => setName(e.target.value)} 
        placeholder="输入名字"
      />
      <button onClick={saveUser}>{editId ? '更新用户' : '添加用户'}</button>
      <ul>
        {users.map(u => (
          <li key={u.id}>
            {u.id}. {u.name} 
            <button onClick={() => editUser(u)}>编辑</button>
            <button onClick={() => deleteUser(u.id)}>删除</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

5、测试

运行后端:

bash 复制代码
npm run dev

运行前端:

bash 复制代码
cd frontend
npm run dev

打开浏览器 http://localhost:5173,你可以:

  • 查看用户列表
  • 添加新用户
  • 编辑已有用户
  • 删除用户

所有数据会保存到 SQLite 数据库 users.db。

6、最终目录结构

cpp 复制代码
my-fullstack-app/
├─ index.js          # 后端
├─ package.json
├─ users.db          # SQLite 数据库
├─ frontend/         # React 前端
│  ├─ index.html
│  ├─ src/
│  │  ├─ App.jsx
│  │  └─ main.jsx
│  └─ package.json
└─ ...

六、Node.js 性能优化指南(企业级)

1、总体原则(先观测再优化)

  • 衡量优先于猜测:先收集指标(延迟、QPS、CPU、内存、事件循环延迟、GC、错误率),再找瓶颈。
  • 先解决慢/热路径:优化 hot path(高频、耗时的代码)比无差别微优化更有效。
  • 分而治之:把系统拆成可独立测量的组件(API、DB、外部依赖、缓存)。
  • 渐进式变更 + 回滚:小步快跑、A/B 测试、灰度发布。
  • 自动化与可观测性:所有优化前后都要有可量化的指标证明。

2、必须搭建的观测与诊断体系(工具与指标)

指标(最低要有):

  • 吞吐(QPS)
  • 平均/95/99 P95/P99 响应时间
  • 错误率(4xx/5xx)
  • CPU/内存/线程数
  • 事件循环延迟(event loop lag)

GC 时间与频率:

  • 链路追踪(分布式追踪:latency per call)

建议工具:

  • APM/Tracing:OpenTelemetry / Jaeger / Zipkin / Datadog / NewRelic
  • Profiling:Clinic.js(doctor/ flame/ bubbleprof)、0x、node --inspect、Chrome DevTools
  • Flamegraph:0x / Linux perf -> flamegraph.pl
  • Live metrics:Prometheus + Grafana(event loop lag、heap、file descriptors)
  • Logs:pino / bunyan(结构化日志 -> stdout -> log aggregator)
  • Load testing:wrk, k6, locust, Artillery

关键命令:

  • 事件循环延迟(node 系统包或 perf_hooks):
cpp 复制代码
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 10 });
h.enable();
// later: h.mean, h.max
  • 启动带 inspector:node --inspect app.js
  • GC 跟踪(排查内存):node --trace-gc --trace-gc-verbose app.js

3、定位瓶颈(诊断流程)

  • 用负载测试重现问题(在测试环境)。
  • 监控指标,确认是 CPU-bound 还是 I/O-bound:
    • CPU-bound:CPU 占用接近 100%,事件循环延迟明显上升。
    • I/O-bound:CPU 空闲、外部依赖(DB/HTTP)延迟高。
  • 采样/火焰图定位热点(Clinic/0x)。
  • 分析 GC 日志(是否频繁 full GC、内存抖动)。
  • 检查同步阻塞调用(fs.readFileSync、加密的同步 API、JSON 序列化大量数据)。
  • 检查线程池耗尽(默认 UV_THREADPOOL_SIZE=4)。

4、代码级优化(高影响项)

(1)、避免阻塞事件循环

  • 绝对避免同步 I/O(*Sync API)和长时间同步计算。
  • 切割大任务:批处理、分片、使用 setImmediate / process.nextTick 谨慎调度微任务。
  • CPU 密集任务 -> 使用 worker_threads 或子进程(child_process/fork)。

示例:worker_threads

cpp 复制代码
// main.js
const { Worker } = require('worker_threads');
function runTask(data) {
  return new Promise((resolve, reject) => {
    const w = new Worker('./worker.js', { workerData: data });
    w.on('message', resolve);
    w.on('error', reject);
  });
}

(2)、使用流(Streams)与 backpressure

  • 处理大文件/大数据应使用 stream 而非一次性读入内存。
  • 使用 stream.pipeline() 以自动处理错误和销毁。
cpp 复制代码
const { pipeline } = require('stream');
pipeline(fs.createReadStream(src), zlib.createGzip(), fs.createWriteStream(dest), err => {});

(3)、减少对象分配与内存抖动

  • 避免在热路径频繁创建对象、字符串拼接(use template literals carefully)。
  • 复用 Buffer(Buffer.allocUnsafe 当心安全)或对象池(connection pooling、buffer pool)。

(4)、优化 JSON 序列化

  • 大量数据传输时,避免 JSON.stringify 在主线程阻塞。可考虑流式 JSON 序列化(例如 JSONStream)。

(5)、避免不必要的同步加解密

  • 加密/哈希/压缩放到线程池或 worker 里。对 PBKDF2 等是关键。

(6)、智能缓存(本地 & 分布式)

  • 缓存热点数据(in-memory LRU,如 lru-cache)和分布式缓存(Redis)。
  • 缓存策略:TTL、主动失效、缓存穿透防护(加互斥锁或空结果缓存)。

(7)、连接池与并发限制

  • 数据库使用连接池(配置合适大小)。
  • 限制外部服务并发(semaphore / p-limit)以防止雪崩。

5、运行时调优(Node 级别参数)

(1)、NODE_ENV

bash 复制代码
export NODE_ENV=production

禁用 dev-only 功能(额外日志、热重载),影响性能。

(2)、GC 与堆大小

  • 设置最大堆:--max-old-space-size=2048(MB)
  • 调试 GC:--trace-gc --trace-gc-verbose

生产中,避免设置过大内存导致 OOM killer 或长 GC 暂停,监测并调整。

(3)、UV_THREADPOOL_SIZE

  • 默认 4。若应用大量 fs/crypto/zlib 调用,增大到 16 或 32(取决于 CPU & workload)。
bash 复制代码
UV_THREADPOOL_SIZE=16 node app.js

(4)、启用并限制抓取

  • 开启 --enable-source-maps 与 --perf-basic-prof 只在需要时使用(调试)。

6、多核与可靠扩缩(进程/线程层)

(1)、Cluster / PM2 / Process Manager

使用 cluster 或 PM2 cluster mode 启用多进程,利用所有 CPU 核心。

cpp 复制代码
// 简单 cluster
const cluster = require('cluster');
if (cluster.isMaster) {
  const cpus = require('os').cpus().length;
  for (let i=0;i<cpus;i++) cluster.fork();
} else {
  require('./app');
}

PM2 更方便:pm2 start app.js -i max

(2)、Worker Threads(处理 CPU 密集)

对于 CPU 密集任务,优先 worker_threads,比 cluster 更轻量、共享内存(SharedArrayBuffer)。

(3)、分布式扩缩

在 Kubernetes 上用 Horizontal Pod Autoscaler,根据 CPU 或自定义指标(请求延迟)扩容。注意避免过短的探针/扩缩轮询导致抖动。

7、I/O 与外部依赖优化

(1)、DB 优化

  • 使用索引、合理 SQL、分页(limit/offset -> cursor)
  • 使用 prepared statements / ORM batch
  • 连接池配置(大小依据 R/W 并发、DB 能力)

(2)、网络请求

  • 使用 keep-alive 复用 TCP 连接(HTTP/1.1 Keep-Alive 或 HTTP/2)。
  • 对外 HTTP 客户端设置连接池(axios/http.Agent)。
cpp 复制代码
const http = require('http');
const agent = new http.Agent({ keepAlive: true, maxSockets: 100 });
  • 使用短超时、防止长尾慢请求占用资源。

(3)、使用 CDN 与边缘缓存

  • 静态内容放 CDN(减少 Node 负载)。
  • SSR 或动态内容考虑边缘计算(Cloudflare Workers / Vercel Edge)。

8、网络层优化(Nginx / Proxy)

  • 在 Node 前放 Nginx 做 TLS 终端、静态缓存、负载均衡、gzip/brotli 和健康检查。示例 Nginx snippet:
cpp 复制代码
server {
  listen 443 ssl;
  gzip on;
  gzip_types text/plain application/json text/css application/javascript;
  location / {
    proxy_set_header Connection "";
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://node_upstream;
    proxy_cache_bypass $http_upgrade;
  }
}
  • 配置 proxy_buffering on/off 根据响应大小调整。

9、安全与稳定性(影响性能的非功能项)

  • Rate limiting(限流):防止 DoS,使用 rate-limit 中间件或 API Gateway。
  • 故障隔离:对外调用使用熔断器(circuit breaker,如 opossum)。
  • 重试策略:有指数退避,避免雪崩。
  • 超时设置:DB、HTTP 客户端、内部调用都应设超时。

10、容器化与 K8s 实践

Docker 最佳实践(减小镜像与启动时间):

  • 基于 node:18-alpine / node:20-bullseye-slim 选择,使用多阶段构建。
  • 非 root 运行,最小化依赖,使用 npm ci --production.
  • 预热依赖(build 阶段)并在运行时只复制产物。

示例 Dockerfile:

bash 复制代码
FROM node:20-bullseye-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:20-bullseye-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --production
USER node
CMD ["node", "dist/index.js"]

K8s 注意:

  • 设置资源 requests/limits(CPU & memory)。防止 OOM/Killed。
  • readiness/liveness probes(HTTP endpoints)。
  • 使用 PodDisruptionBudget、合理滚动升级策略。
  • 使用 Vertical Pod Autoscaler + HPA 基于自定义指标(比如平均响应时间)。

11、日志、指标与可观测性实践

  • 结构化日志(JSON),异步写 stdout,配合 ELK/EFK。
  • 日志级别分离(error/warn/info/debug),生产默认 info 或 warn。
  • 捕获 unhandledRejection 与 uncaughtException:记录并优雅退出(不要继续运行)。
cpp 复制代码
process.on('unhandledRejection', (r) => {
  console.error('Unhandled Rejection', r);
});
  • 导出 Prometheus 指标:event loop lag、heap usage、GC pause、requests total、latencies。

12、性能测试与回归(CI 集成)

  • 在 CI 中加入性能基线测试(使用 k6/wrk),防止 PR 引入回归。
  • 每次依赖升级、Node 升级后都跑性能回归。
  • 在 Canary/灰度环境先跑真实流量采样。

13、常见场景与解决方案速查表

问题 可能原因 解决建议
高延迟 P95/P99 外部 DB 慢 / 队列堆积 增加缓存 / 限流 / 异步化 / DB 优化
CPU 飙高 同步操作或计算 抽离到 worker_threads 或微服务
内存不断增长 内存泄露 / 大对象缓存 heapdump 分析、避免全局缓存、限制队列长度
频繁 GC 堆太大或对象分配过多 减少分配、调整 GC 参数、缩小堆
线程池耗尽 大量 fs/crypto/zlib 并发 增加 UV_THREADPOOL_SIZE 或拆分任务到 worker

14、十四、示例监控指标导出(Prometheus 简单实现)

cpp 复制代码
const client = require('prom-client');
const gauge = new client.Gauge({ name: 'node_event_loop_delay_mean', help: '...' });
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay();
h.enable();
setInterval(() => gauge.set(h.mean / 1e6), 5000); // ms

15、优先级清单(落地执行顺序)

  • 建监控与日志(Prometheus + Grafana + structured logs)
  • 加入事件循环 & heap 指标采集
  • 压测复现问题(k6/wrk),收集 baseline
  • 采样分析(Clinic / 0x / flamegraph)定位热点
  • 针对热点做代码优化(流、worker、缓存)
  • 调整运行时(UV_THREADPOOL_SIZE、--max-old-space-size)
  • 部署多进程(cluster/PM2)并做灰度发布
  • 持续回归测试 & 自动告警

16、常用命令 & 快速检查清单

  • 查看 Node 版本:node -v(尽量用 LTS/Active 支持版本)
  • 启用 inspector:node --inspect-brk app.js
  • 事件循环延迟(perf_hooks 采样)
  • 增加线程池:UV_THREADPOOL_SIZE=16 node app.js
  • 限制内存:node --max-old-space-size=2048 app.js
  • PM2 多进程:pm2 start app.js -i max
  • 压测:wrk -t12 -c400 -d30s http://host:port/path
  • 火焰图:clinic flame -- node app.js(clinic 会生成可视化)
相关推荐
没事别瞎琢磨2 小时前
十一、审计与 Run Session——每一步操作都被记录
人工智能·node.js
没事别瞎琢磨2 小时前
十六、AgentSandbox——把所有模块串起来的编排类
人工智能·node.js
没事别瞎琢磨2 小时前
十二、网络代理与白名单规则引擎
人工智能·node.js
没事别瞎琢磨2 小时前
十四、Git Worktree 隔离执行
人工智能·node.js
没事别瞎琢磨3 小时前
十、统一 Runner 入口——能力检测与模式回退
人工智能·node.js
没事别瞎琢磨3 小时前
八、环境隔离——构建安全的子进程环境
人工智能·node.js
没事别瞎琢磨4 小时前
六、输出捕获与截断
人工智能·node.js
没事别瞎琢磨4 小时前
七、敏感路径预检——Protected Paths
人工智能·node.js
没事别瞎琢磨4 小时前
五、进程执行——spawn、超时与进程树清理
人工智能·node.js
没事别瞎琢磨4 小时前
四、命令风险分级与审批策略
人工智能·node.js