后端修炼篇⑥:项目部署与性能优化 - 从开发到上线
掌握生产环境部署技能,让应用稳定高效运行🚀
学习目标
- ✅ 掌握Linux服务器环境配置
- ✅ 学会使用Docker容器化部署
- ✅ 掌握Nginx反向代理和负载均衡
- ✅ 学会应用性能监控和优化技巧
- ✅ 实现自动化部署和持续集成
📖📖 教程概览
项目部署是开发的最后一步,也是最重要的一步。本教程将带你从零开始配置生产环境,实现应用的容器化部署、性能优化和自动化运维。
💻💻 第一步:服务器环境配置
1.1 Linux服务器基础
服务器选择:根据业务需求选择合适的云服务器
- 小型项目:1核2G配置,月付约30-50元
- 中型项目:2核4G配置,月付约80-120元
- 大型项目:4核8G以上,按需配置
1.2 服务器安全配置
# 1. 更新系统
sudo apt update && sudo apt upgrade -y
# 2. 创建新用户(避免使用root)
adduser deployer
usermod -aG sudo deployer
# 3. 配置SSH密钥登录
mkdir ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# 4. 禁用密码登录
sudo vim /etc/ssh/sshd_config
# 修改以下配置:
# PasswordAuthentication no
# PermitRootLogin no
# 5. 配置防火墙
sudo ufw allow ssh
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable1.3 基础软件安装
# 安装Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# 安装PM2进程管理
sudo npm install -g pm2
# 安装Nginx
sudo apt install nginx -y
# 安装MongoDB
wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
# 安装Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER🛠🛠 第二步:Docker容器化部署
2.1 Docker基础概念
- 镜像(Image):应用的打包模板
- 容器(Container):镜像的运行实例
- 仓库(Registry):镜像的存储和分发中心
- Dockerfile:镜像构建脚本
2.2 创建Dockerfile
# Dockerfile
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制源代码
COPY . .
# 创建非root用户
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# 更改文件所有者
RUN chown -R nextjs:nodejs /app
USER nextjs
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["npm", "start"]2.3 Docker Compose编排
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- MONGODB_URI=mongodb://mongo:27017/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- mongo
- redis
restart: unless-stopped
mongo:
image: mongo:6
ports:
- "27017:27017"
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
volumes:
- mongodb_data:/data/db
restart: unless-stopped
redis:
image: redis:alpine
ports:
- "6379:6379"
command: redis-server --appendonly yes
volumes:
- redis_data:/data
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped
volumes:
mongodb_data:
redis_data:2.4 构建和运行
# 构建镜像
docker-compose build
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f app
# 停止服务
docker-compose down🌟🌟 第三步:Nginx配置与优化
3.1 Nginx基础配置
# nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# 基础优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
# 上游服务配置
upstream nodejs_app {
server app:3000;
keepalive 32;
}
# 服务器配置
server {
listen 80;
server_name yourdomain.com;
# 静态文件缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API代理
location /api {
proxy_pass http://nodejs_app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# 静态文件服务
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
}3.2 SSL证书配置
# 使用Certbot获取免费SSL证书
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com
# 自动续期配置
sudo crontab -e
# 添加以下行:
# 0 12 * * * /usr/bin/certbot renew --quiet🎮🎮 第四步:性能监控与优化
4.1 应用性能监控
// utils/monitoring.js
const prometheus = require('prom-client');
// 收集默认指标
const collectDefaultMetrics = prometheus.collectDefaultMetrics;
collectDefaultMetrics({ timeout: 5000 });
// 自定义指标
const httpRequestDurationMicroseconds = new prometheus.Histogram({
name: 'http_request_duration_ms',
help: 'HTTP请求持续时间',
labelNames: ['method', 'route', 'code'],
buckets: [0.1, 5, 15, 50, 100, 500]
});
// 请求监控中间件
const monitoringMiddleware = (req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
httpRequestDurationMicroseconds
.labels(req.method, req.route?.path || req.path, res.statusCode)
.observe(duration);
});
next();
};
// 指标暴露端点
app.get('/metrics', async (req, res) => {
res.set('Content-Type', prometheus.register.contentType);
res.end(await prometheus.register.metrics());
});
module.exports = { monitoringMiddleware };4.2 数据库性能优化
// config/database.js
const mongoose = require('mongoose');
// 连接配置
mongoose.connect(process.env.MONGODB_URI, {
maxPoolSize: 10, // 连接池大小
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
});
// 索引优化
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
username: { type: String, unique: true },
createdAt: { type: Date, default: Date.now }
});
// 创建复合索引
userSchema.index({ email: 1, createdAt: -1 });
userSchema.index({ username: 1 });
// 查询优化示例
const getActiveUsers = async () => {
return await User.find({ isActive: true })
.select('username email createdAt')
.sort({ createdAt: -1 })
.limit(100)
.lean(); // 返回纯JavaScript对象,提高性能
};4.3 Redis缓存优化
// utils/cache.js
const redis = require('redis');
class CacheService {
constructor() {
this.client = redis.createClient({
url: process.env.REDIS_URL
});
this.client.connect();
this.client.on('error', (err) => {
console.error('Redis错误:', err);
});
}
// 设置缓存
async set(key, value, expireSeconds = 3600) {
try {
await this.client.set(key, JSON.stringify(value), {
EX: expireSeconds
});
} catch (error) {
console.error('缓存设置失败:', error);
}
}
// 获取缓存
async get(key) {
try {
const data = await this.client.get(key);
return data ? JSON.parse(data) : null;
} catch (error) {
console.error('缓存获取失败:', error);
return null;
}
}
// 删除缓存
async del(key) {
try {
await this.client.del(key);
} catch (error) {
console.error('缓存删除失败:', error);
}
}
// 缓存用户数据示例
async cacheUserProfile(userId, userData) {
const key = `user:profile:${userId}`;
await this.set(key, userData, 1800); // 缓存30分钟
}
}
module.exports = new CacheService();🚀🚀 第五步:自动化部署与CI/CD
5.1 GitHub Actions自动化部署
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run linting
run: npm run lint
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Deploy to server
uses: appleboy/ssh-action@v0.1.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
cd /opt/app
git pull origin main
npm ci --production
docker-compose down
docker-compose up -d --build
echo "部署成功"5.2 PM2进程管理
// ecosystem.config.js
module.exports = {
apps: [{
name: 'my-app',
script: 'server.js',
instances: 'max', // 使用所有CPU核心
exec_mode: 'cluster', // 集群模式
env: {
NODE_ENV: 'development',
PORT: 3000
},
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
// 监控配置
watch: false,
max_memory_restart: '1G',
// 日志配置
log_file: './logs/combined.log',
out_file: './logs/out.log',
error_file: './logs/error.log',
time: true,
// 重启策略
autorestart: true,
max_restarts: 10,
min_uptime: '10s'
}]
};
// PM2常用命令
// pm2 start ecosystem.config.js --env production
// pm2 monit
// pm2 logs
// pm2 reload all
// pm2 delete all5.3 健康检查端点
// routes/health.js
const router = require('express').Router();
const mongoose = require('mongoose');
const redis = require('../utils/redis');
router.get('/health', async (req, res) => {
const checks = {
server: 'ok',
database: 'checking',
redis: 'checking',
uptime: process.uptime(),
timestamp: new Date().toISOString()
};
try {
// 数据库健康检查
await mongoose.connection.db.admin().ping();
checks.database = 'ok';
} catch (error) {
checks.database = 'error';
}
try {
// Redis健康检查
await redis.ping();
checks.redis = 'ok';
} catch (error) {
checks.redis = 'error';
}
const status = checks.database === 'ok' && checks.redis === 'ok' ? 200 : 503;
res.status(status).json({
success: status === 200,
data: checks
});
});
module.exports = router;📚📚 「后端修炼篇」系列总结
六篇教程学习路径回顾:
- Node.js入门 - 开启JavaScript全栈之旅 ✅
- 数据库操作 - MySQL与MongoDB实战 ✅
- RESTful API设计 - 构建规范接口 ✅
- 用户认证与授权 - JWT实战 ✅
- 文件上传与云存储 - 多媒体处理 ✅
- 项目部署与性能优化 - 从开发到上线 ✅
您已掌握的后端核心技能:
- ✅ 能够使用Node.js构建完整的后端应用
- ✅ 掌握数据库设计和优化技巧
- ✅ 能够设计规范的RESTful API接口
- ✅ 实现安全的用户认证和权限控制
- ✅ 处理文件上传和云存储集成
- ✅ 部署应用到生产环境并进行性能优化
💡💡 生产环境常见问题
Q:如何选择服务器配置?
A:根据预估流量选择,小型项目1核2G起步,预留30%性能余量
Q:Docker和虚拟机有什么区别?
A:Docker更轻量,启动更快,资源占用更少,适合微服务架构
Q:如何监控应用性能?
A:使用PM2内置监控、添加业务指标、集成APM工具(如New Relic)
Q:数据库如何备份?
A:定期自动备份到云存储,重要数据实现异地容灾
🎉🎉 系列完结与进阶学习
恭喜你完成了「后端修炼篇」全部六篇教程!
你已经从一个后端新手成长为能够独立开发、部署和维护生产级应用的开发者。接下来可以继续学习:
- 微服务架构:Spring Cloud、Dubbo、gRPC
- 消息队列:RabbitMQ、Kafka、Redis Stream
- 搜索引擎:Elasticsearch、Solr
- DevOps:Kubernetes、Jenkins、Terraform
- 云原生:Service Mesh、Serverless
记住,技术学习永无止境,保持好奇心和实践精神,你一定能成为优秀的高级工程师!
版权申明
本文系作者 @sgyyds 原创发布在孙哥博客站点。未经许可,禁止转载。
暂无评论数据