当前位置:首页 > 未命名 > 正文内容

Node.js性能优化实战手册

廖万里8小时前未命名1

Node.js性能基础

Node.js基于V8引擎,采用事件驱动、非阻塞I/O模型,天然适合高并发场景。但要发挥其最大性能,需要深入理解其机制并进行针对性优化。

性能瓶颈识别

// 使用perf_hooks测量
const { performance, PerformanceObserver } = require('perf_hooks');

// 测量函数执行时间
performance.mark('start');
// ... 代码执行
performance.mark('end');
performance.measure('My Function', 'start', 'end');

const observer = new PerformanceObserver((list) => {
  const entries = list.getEntries();
  entries.forEach((entry) => {
    console.log(`${entry.name}: ${entry.duration}ms`);
  });
});
observer.observe({ entryTypes: ['measure'] });

// 使用console.time
console.time('operation');
// ... 操作
console.timeEnd('operation');

V8优化

优化编译

// V8优化提示
// 1. 保持对象形状一致
// 好
function Point(x, y) {
  this.x = x;
  this.y = y;
}

// 坏 - 隐藏类改变
function Point(x, y) {
  if (x) this.x = x;
  if (y) this.y = y;
}

// 2. 避免修改数组类型
// 好
const arr = [1, 2, 3];  // PACKED_SMI_ELEMENTS

// 坏 - 降级为PACKED_ELEMENTS
arr.push('string');

// 3. 单态操作
class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }
  
  getArea() {
    return this.width * this.height;  // 单态
  }
}

内存管理

// 查看内存使用
const used = process.memoryUsage();
console.log({
  rss: `${Math.round(used.rss / 1024 / 1024)}MB`,
  heapTotal: `${Math.round(used.heapTotal / 1024 / 1024)}MB`,
  heapUsed: `${Math.round(used.heapUsed / 1024 / 1024)}MB`,
  external: `${Math.round(used.external / 1024 / 1024)}MB`
});

// 手动触发GC(生产环境禁用)
if (global.gc) {
  global.gc();
}

// 内存泄漏检测
const { heapSnapshot } = require('v8');
// 生成堆快照
const snapshot = heapSnapshot.writeHeapSnapshot();
console.log(`Heap snapshot written to ${snapshot}`);

// Set和Map清理
let cache = new Map();
function cleanup() {
  for (const [key, value] of cache) {
    if (value.expired) cache.delete(key);
  }
}
setInterval(cleanup, 60000);

异步优化

Promise优化

// 并行执行
async function fetchAll() {
  const [users, posts, comments] = await Promise.all([
    fetchUsers(),
    fetchPosts(),
    fetchComments()
  ]);
  return { users, posts, comments };
}

// 错误处理
async function fetchWithRetry(fn, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise(r => setTimeout(r, 1000 * (i + 1)));
    }
  }
}

// 限制并发数
async function limitConcurrency(tasks, limit) {
  const results = [];
  const executing = [];
  
  for (const task of tasks) {
    const p = Promise.resolve().then(() => task());
    results.push(p);
    
    if (limit <= tasks.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= limit) {
        await Promise.race(executing);
      }
    }
  }
  
  return Promise.all(results);
}

事件循环优化

// 检查事件循环延迟
const { monitorEventLoopDelay } = require('perf_hooks');
const h = monitorEventLoopDelay({ resolution: 10 });
h.enable();

setInterval(() => {
  console.log({
    mean: h.mean,
    max: h.max,
    min: h.min
  });
}, 10000);

// 分片处理大数据
async function processLargeArray(array, chunkSize = 1000) {
  const results = [];
  
  for (let i = 0; i < array.length; i += chunkSize) {
    const chunk = array.slice(i, i + chunkSize);
    results.push(...chunk.map(item => processItem(item)));
    
    // 让出事件循环
    await new Promise(setImmediate);
  }
  
  return results;
}

// 使用worker_threads处理CPU密集任务
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename, { workerData: largeData });
  worker.on('message', (result) => console.log(result));
} else {
  const result = heavyComputation(workerData);
  parentPort.postMessage(result);
}

HTTP优化

// HTTP/2服务器
const http2 = require('http2');
const fs = require('fs');

const server = http2.createSecureServer({
  key: fs.readFileSync('key.pem'),
  cert: fs.readFileSync('cert.pem')
});

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html',
    ':status': 200
  });
  stream.end('

Hello HTTP/2

'); }); // Keep-Alive连接 const http = require('http'); const agent = new http.Agent({ keepAlive: true, maxSockets: 50, maxFreeSockets: 10, timeout: 60000 }); // 响应压缩 const zlib = require('zlib'); const { createGzip } = zlib; function compressResponse(req, res, data) { const acceptEncoding = req.headers['accept-encoding'] || ''; if (acceptEncoding.includes('gzip')) { res.writeHead(200, { 'Content-Encoding': 'gzip' }); zlib.gzip(data, (_, result) => res.end(result)); } else { res.end(data); } } // 缓存策略 const etag = require('etag'); function serveWithCache(req, res, content) { const e = etag(content); if (req.headers['if-none-match'] === e) { res.writeHead(304); return res.end(); } res.writeHead(200, { 'ETag': e, 'Cache-Control': 'public, max-age=3600' }); res.end(content); }

诊断工具

// 诊断报告
const { writeHeapSnapshot, getHeapStatistics } = require('v8');
const { generateHeapSnapshot } = require('node:vm');

// 生成报告
process.report.writeReport('./report.json');

// Clinic.js分析
// clinic doctor -- node app.js
// clinic flame -- node app.js
// clinic bubbleprof -- node app.js

// 0x火焰图
// 0x -o flamegraph.html app.js

// 内置分析器
// node --prof app.js
// node --prof-process isolate-*.log

最佳实践

  1. 使用最新LTS版本:获取性能改进
  2. 启用严格模式:帮助V8优化
  3. 避免同步操作:阻塞事件循环
  4. 使用连接池:复用数据库连接
  5. 合理使用缓存:减少重复计算
  6. 监控内存:及时发现泄漏

Node.js性能优化是一个持续过程,需要结合监控数据不断调整。

Node.js Event Loop V8 Engine libuv Node.js运行时架构

本文链接:https://www.kkkliao.cn/?id=756 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。