返回博客列表
后端开发
Node.js 性能优化实战
2025-09-08
12 分钟阅读
Node.js性能优化后端

Node.js 性能优化实战
Node.js 作为服务端 JavaScript 运行时,在构建高性能应用方面有着独特的优势。本文将分享一些实用的性能优化技巧和最佳实践。
性能监控基础
1. 使用内置性能监控
const { performance, PerformanceObserver } = require('perf_hooks')
// 监控函数执行时间
function measureTime(fn) {
const start = performance.now()
const result = fn()
const end = performance.now()
console.log(`执行时间: ${end - start} 毫秒`)
return result
}
// 监控内存使用
function logMemoryUsage() {
const used = process.memoryUsage()
console.log('内存使用情况:')
for (let key in used) {
console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`)
}
}
2. 使用第三方监控工具
// 使用 clinic.js 进行性能分析
const clinic = require('@nearform/clinic')
// 启动性能分析
clinic.doctor({
collectOnFailure: true,
dest: './clinic-results'
})
内存优化
1. 避免内存泄漏
// 错误示例:未清理的定时器
function badExample() {
setInterval(() => {
console.log('定时器运行中...')
}, 1000)
// 没有清理定时器,会导致内存泄漏
}
// 正确示例:清理定时器
function goodExample() {
const intervalId = setInterval(() => {
console.log('定时器运行中...')
}, 1000)
// 在适当的时候清理
setTimeout(() => {
clearInterval(intervalId)
}, 5000)
}
2. 使用对象池
class ObjectPool {
constructor(createFn, resetFn, initialSize = 10) {
this.createFn = createFn
this.resetFn = resetFn
this.pool = []
// 预创建对象
for (let i = 0; i < initialSize; i++) {
this.pool.push(createFn())
}
}
acquire() {
if (this.pool.length > 0) {
return this.pool.pop()
}
return this.createFn()
}
release(obj) {
this.resetFn(obj)
this.pool.push(obj)
}
}
// 使用示例
const userPool = new ObjectPool(
() => ({ id: null, name: '', email: '' }),
(user) => { user.id = null; user.name = ''; user.email = '' }
)
异步处理优化
1. 使用 Promise.all 并行处理
// 错误示例:串行处理
async function badExample() {
const user1 = await fetchUser(1)
const user2 = await fetchUser(2)
const user3 = await fetchUser(3)
return [user1, user2, user3]
}
// 正确示例:并行处理
async function goodExample() {
const [user1, user2, user3] = await Promise.all([
fetchUser(1),
fetchUser(2),
fetchUser(3)
])
return [user1, user2, user3]
}
2. 使用流处理大文件
const fs = require('fs')
const { Transform } = require('stream')
// 创建转换流
const processData = new Transform({
objectMode: true,
transform(chunk, encoding, callback) {
// 处理数据块
const processed = processChunk(chunk)
callback(null, processed)
}
})
// 使用流处理大文件
function processLargeFile(inputPath, outputPath) {
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(inputPath)
const writeStream = fs.createWriteStream(outputPath)
readStream
.pipe(processData)
.pipe(writeStream)
.on('finish', resolve)
.on('error', reject)
})
}
数据库优化
1. 连接池管理
const mysql = require('mysql2/promise')
// 创建连接池
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'mydb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
acquireTimeout: 60000,
timeout: 60000
})
// 使用连接池
async function getUsers() {
const connection = await pool.getConnection()
try {
const [rows] = await connection.execute('SELECT * FROM users')
return rows
} finally {
connection.release()
}
}
2. 查询优化
// 使用索引优化查询
async function getUsersByEmail(email) {
const query = 'SELECT * FROM users WHERE email = ?'
const [rows] = await pool.execute(query, [email])
return rows
}
// 使用分页避免大量数据查询
async function getUsersPaginated(page = 1, limit = 10) {
const offset = (page - 1) * limit
const query = 'SELECT * FROM users LIMIT ? OFFSET ?'
const [rows] = await pool.execute(query, [limit, offset])
return rows
}
缓存策略
1. 内存缓存
const NodeCache = require('node-cache')
// 创建缓存实例
const cache = new NodeCache({
stdTTL: 600, // 默认过期时间 10 分钟
checkperiod: 120 // 检查过期时间 2 分钟
})
// 缓存函数
function withCache(key, ttl = 600) {
return function(target, propertyName, descriptor) {
const method = descriptor.value
descriptor.value = async function(...args) {
const cacheKey = `${key}:${JSON.stringify(args)}`
// 尝试从缓存获取
let result = cache.get(cacheKey)
if (result) {
console.log('从缓存获取数据')
return result
}
// 执行原函数
result = await method.apply(this, args)
// 存储到缓存
cache.set(cacheKey, result, ttl)
console.log('数据已缓存')
return result
}
}
}
// 使用示例
class UserService {
@withCache('user', 300)
async getUserById(id) {
// 模拟数据库查询
return await db.query('SELECT * FROM users WHERE id = ?', [id])
}
}
2. Redis 缓存
const redis = require('redis')
const client = redis.createClient()
// 缓存装饰器
function redisCache(key, ttl = 600) {
return function(target, propertyName, descriptor) {
const method = descriptor.value
descriptor.value = async function(...args) {
const cacheKey = `${key}:${JSON.stringify(args)}`
try {
// 尝试从 Redis 获取
const cached = await client.get(cacheKey)
if (cached) {
console.log('从 Redis 缓存获取数据')
return JSON.parse(cached)
}
// 执行原函数
const result = await method.apply(this, args)
// 存储到 Redis
await client.setex(cacheKey, ttl, JSON.stringify(result))
console.log('数据已存储到 Redis')
return result
} catch (error) {
console.error('缓存错误:', error)
return await method.apply(this, args)
}
}
}
}
代码优化技巧
1. 避免阻塞操作
// 错误示例:同步文件操作
function badExample() {
const data = fs.readFileSync('large-file.txt', 'utf8')
return processData(data)
}
// 正确示例:异步文件操作
async function goodExample() {
const data = await fs.promises.readFile('large-file.txt', 'utf8')
return processData(data)
}
2. 使用 Worker Threads
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads')
// 主线程
if (isMainThread) {
function runWorker(data) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: data
})
worker.on('message', resolve)
worker.on('error', reject)
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker 停止,退出码: ${code}`))
}
})
})
}
// 使用 Worker
async function processLargeData(data) {
const result = await runWorker(data)
return result
}
} else {
// Worker 线程
const result = heavyComputation(workerData)
parentPort.postMessage(result)
}
应用架构优化
1. 微服务架构
// 服务发现
const consul = require('consul')
class ServiceRegistry {
constructor() {
this.consul = consul()
}
async registerService(service) {
await this.consul.agent.service.register({
name: service.name,
address: service.address,
port: service.port,
check: {
http: `http://${service.address}:${service.port}/health`,
interval: '10s'
}
})
}
async discoverService(serviceName) {
const services = await this.consul.health.service({
service: serviceName,
passing: true
})
return services[0]
}
}
2. 负载均衡
const cluster = require('cluster')
const numCPUs = require('os').cpus().length
if (cluster.isMaster) {
console.log(`主进程 ${process.pid} 正在运行`)
// 创建工作进程
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
cluster.on('exit', (worker, code, signal) => {
console.log(`工作进程 ${worker.process.pid} 已退出`)
cluster.fork() // 重启工作进程
})
} else {
// 工作进程
const express = require('express')
const app = express()
app.get('/', (req, res) => {
res.json({
message: 'Hello World!',
pid: process.pid
})
})
app.listen(3000, () => {
console.log(`工作进程 ${process.pid} 已启动`)
})
}
监控和调试
1. 性能指标收集
const prometheus = require('prom-client')
// 创建指标
const httpRequestDuration = new prometheus.Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP 请求持续时间',
labelNames: ['method', 'route', 'status_code']
})
const httpRequestTotal = new prometheus.Counter({
name: 'http_requests_total',
help: 'HTTP 请求总数',
labelNames: ['method', 'route', 'status_code']
})
// 中间件
function metricsMiddleware(req, res, next) {
const start = Date.now()
res.on('finish', () => {
const duration = (Date.now() - start) / 1000
const labels = {
method: req.method,
route: req.route?.path || req.path,
status_code: res.statusCode
}
httpRequestDuration.observe(labels, duration)
httpRequestTotal.inc(labels)
})
next()
}
2. 健康检查
const express = require('express')
const app = express()
// 健康检查端点
app.get('/health', async (req, res) => {
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
version: process.version
}
// 检查数据库连接
try {
await checkDatabaseConnection()
health.database = 'ok'
} catch (error) {
health.database = 'error'
health.status = 'error'
}
const statusCode = health.status === 'ok' ? 200 : 503
res.status(statusCode).json(health)
})
async function checkDatabaseConnection() {
// 实现数据库连接检查
return true
}
总结
Node.js 性能优化是一个持续的过程,需要从多个方面入手:
- 监控和测量:建立完善的性能监控体系
- 内存管理:避免内存泄漏,合理使用内存
- 异步处理:充分利用 Node.js 的异步特性
- 数据库优化:使用连接池,优化查询
- 缓存策略:合理使用各种缓存技术
- 代码优化:避免阻塞操作,使用 Worker Threads
- 架构设计:采用微服务和负载均衡
记住,性能优化不是一蹴而就的,需要根据实际应用场景和性能瓶颈进行有针对性的优化。