阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 生产环境配置与调优

生产环境配置与调优

作者:陈川 阅读数:7848人阅读 分类: Node.js

生产环境配置与调优

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌