生产环境配置与调优
生产环境配置与调优
Express作为Node.js最流行的Web框架之一,在生产环境中需要特别注意性能、安全性和稳定性。合理的配置和调优能显著提升应用吞吐量,降低响应延迟,同时保障系统安全。
环境变量管理
生产环境必须使用环境变量来管理敏感配置。dotenv包可以方便地加载.env文件,但生产环境应该直接通过系统环境变量注入:
// config.js
const config = {
port: process.env.PORT || 3000,
dbUrl: process.env.DATABASE_URL,
jwtSecret: process.env.JWT_SECRET,
nodeEnv: process.env.NODE_ENV || 'development'
}
永远不要将敏感信息硬编码在代码中或提交到版本控制系统。对于复杂的配置,可以使用convict等配置验证库:
const convict = require('convict');
const config = convict({
env: {
doc: "应用环境",
format: ["production", "development", "test"],
default: "development",
env: "NODE_ENV"
},
port: {
doc: "服务端口",
format: "port",
default: 3000,
env: "PORT"
}
});
性能调优
启用压缩
使用compression中间件可以显著减少响应体积:
const compression = require('compression');
app.use(compression({
level: 6, // 压缩级别1-9
threshold: '1kb', // 大于1kb才压缩
filter: (req) => !req.headers['x-no-compression']
}));
集群模式
利用多核CPU启动集群:
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
const app = require('./app');
app.listen(3000);
}
缓存策略
合理设置HTTP缓存头:
app.use((req, res, next) => {
if (req.path.match(/\.(jpg|png|css|js)$/)) {
res.set('Cache-Control', 'public, max-age=31536000');
}
next();
});
对于API响应,可以使用ETag:
app.set('etag', 'strong'); // 使用强ETag验证
安全配置
Helmet中间件
Helmet提供了多种安全相关的HTTP头设置:
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "trusted.cdn.com"]
}
},
hsts: {
maxAge: 63072000,
includeSubDomains: true,
preload: true
}
}));
请求限制
防止暴力破解和DDoS攻击:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个IP限制100次请求
message: '请求过于频繁,请稍后再试'
});
app.use('/api/', limiter);
日志记录
生产环境需要完整的访问日志和错误日志:
const morgan = require('morgan');
const fs = require('fs');
const path = require('path');
// 访问日志
const accessLogStream = fs.createWriteStream(
path.join(__dirname, 'access.log'),
{ flags: 'a' }
);
app.use(morgan('combined', { stream: accessLogStream }));
// 错误日志
process.on('uncaughtException', (err) => {
fs.appendFileSync('error.log', `${new Date().toISOString()} - ${err.stack}\n`);
process.exit(1);
});
对于分布式系统,建议使用Winston或Bunyan等更强大的日志库,并集成日志收集系统如ELK。
数据库优化
连接池配置
数据库连接池的合理配置对性能至关重要:
const { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20, // 最大连接数
idleTimeoutMillis: 30000, // 空闲连接超时
connectionTimeoutMillis: 2000 // 连接超时
});
查询优化
使用ORM时要注意N+1查询问题:
// 不好的做法 - 会产生N+1查询
const users = await User.findAll();
const userWithPosts = await Promise.all(users.map(user =>
user.getPosts()
));
// 好的做法 - 预加载关联数据
const users = await User.findAll({
include: [{ model: Post }]
});
进程管理
使用PM2等进程管理器可以确保应用崩溃后自动重启:
pm2 start app.js -i max --name "api-server" --update-env
PM2配置示例:
module.exports = {
apps: [{
name: 'api',
script: './app.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '1G',
env: {
NODE_ENV: 'production'
}
}]
}
监控与告警
集成健康检查端点:
app.get('/health', (req, res) => {
res.json({
status: 'UP',
uptime: process.uptime(),
memoryUsage: process.memoryUsage(),
dbStatus: checkDbConnection()
});
});
使用Prometheus收集指标:
const client = require('prom-client');
const collectDefaultMetrics = client.collectDefaultMetrics;
collectDefaultMetrics({ timeout: 5000 });
app.get('/metrics', async (req, res) => {
res.set('Content-Type', client.register.contentType);
res.end(await client.register.metrics());
});
静态资源优化
使用CDN分发静态资源:
app.use('/static', express.static('public', {
maxAge: '1y',
setHeaders: (res, path) => {
if (path.endsWith('.br')) {
res.set('Content-Encoding', 'br');
} else if (path.endsWith('.gz')) {
res.set('Content-Encoding', 'gzip');
}
}
}));
预压缩静态文件:
# 使用Brotli和Gzip预压缩
find public -type f -exec brotli -k {} \;
find public -type f -exec gzip -k {} \;
错误处理
生产环境需要友好的错误处理:
// 404处理
app.use((req, res, next) => {
res.status(404).json({
error: 'Not Found',
path: req.path
});
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: process.env.NODE_ENV === 'development' ?
err.message : 'Internal Server Error'
});
});
对于异步错误,使用express-async-errors:
require('express-async-errors');
app.get('/async', async (req, res) => {
throw new Error('Async error');
// 不需要try/catch,中间件会自动捕获
});
部署优化
使用Docker部署时优化镜像:
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
USER node
EXPOSE 3000
CMD ["node", "app.js"]
构建优化:
# 多阶段构建减小镜像大小
docker build -t myapp .
# 使用.dockerignore排除不需要的文件
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn