Files
astro-jiao77.cn/docs/SINGLE_VPS_DEPLOYMENT_PLAN.md
2025-10-21 01:44:01 +08:00

27 KiB
Raw Blame History

🚀 单机 VPS 部署方案 - 优化 TodoList

部署环境:单机 VPS公网 IP + 大带宽 + 100GB 存储) 优化方向:资源优化、单机部署、简化运维 项目周期4-5 周 | 总任务数72 项 | 优先级分布P0(20) | P1(30) | P2(15) | P3(7)


📋 环境特点分析

优势

  • 单一公网 IP简化网络配置
  • 大带宽支持高并发
  • 100GB 存储足够应用 + 数据库 + 备份

⚠️ 制约

  • 单机故障 = 全部服务宕机
  • 内存/CPU 有限(需要优化)
  • 需要更严格的监控和备份

🎯 优化策略

  1. 容器精简 - 使用 Alpine 基础镜像
  2. 资源共享 - 数据库、应用、Web 服务器在同一机器
  3. 缓存优先 - Redis 缓存热数据
  4. 监控告警 - 及时发现问题
  5. 自动备份 - 防止数据丢失

🎯 第一阶段:环境准备与优化(第 1 周)

🔴 P0 任务VPS 环境初始化

1.1 VPS 系统准备

  • SSH 连接 VPS验证系统版本建议 Ubuntu 20.04 LTS
  • 更新系统:sudo apt update && apt upgrade -y
  • 安装基础工具:sudo apt install -y curl wget git htop
  • 配置防火墙UFW
    sudo ufw enable
    sudo ufw allow 22/tcp    # SSH
    sudo ufw allow 80/tcp    # HTTP
    sudo ufw allow 443/tcp   # HTTPS
    
  • 配置时区和 NTP
  • 创建普通用户用于应用运行(非 root

1.2 Docker 和 Docker Compose 安装

  • 安装 Dockercurl -fsSL https://get.docker.com | sh
  • 配置 Docker 权限:添加用户到 docker 组
  • 安装 Docker Compose最新版本
  • 验证 Docker 和 Compose 可用性

1.3 域名和 SSL 配置

  • 配置域名 DNS 解析到公网 IP
  • 申请 Let's Encrypt SSL 证书(使用 Certbot
  • 配置 SSL 证书自动续期
  • 测试 HTTPS 连接

1.4 存储规划

  • 检查磁盘使用情况:df -h
  • 规划存储分配100GB
    系统20GB
    数据库30GB
    应用20GB
    备份20GB
    日志10GB
    
  • 创建数据目录结构

🟠 P1 任务:后端项目创建

1.5 创建后端项目

  • 在 VPS 上克隆项目:git clone <repo> /home/app/backend
  • 创建 /backend 目录结构
    backend/
    ├── src/
    │   ├── server.ts
    │   ├── config/
    │   ├── routes/
    │   ├── controllers/
    │   ├── middleware/
    │   ├── database/
    │   └── types/
    ├── docker/
    │   ├── Dockerfile
    │   └── .dockerignore
    ├── scripts/
    │   ├── db-init.sql
    │   └── backup.sh
    ├── package.json
    ├── tsconfig.json
    └── .env
    
  • 本地初始化 Node.js 项目npm init
  • 编写最小化 package.json仅必需依赖

1.6 依赖选择(针对单机优化)

  • 后端依赖:
    {
      "express": "^4.18.2",
      "pg": "^8.10.0",
      "cors": "^2.8.5",
      "dotenv": "^16.3.1",
      "zod": "^3.22.4",
      "pino": "^8.16.1"
    }
    
  • 开发依赖:
    {
      "typescript": "^5.2.2",
      "ts-node": "^10.9.1",
      "nodemon": "^3.0.1",
      "@types/express": "^4.17.20",
      "@types/node": "^20.8.0",
      "jest": "^29.7.0",
      "@types/jest": "^29.5.6"
    }
    
  • 移除不必要包@astrojs/node, 重量级 ORM 等

🟡 P2 任务:文档和规划

1.7 部署文档编写

  • 编写 VPS 部署指南
  • 记录环境配置清单
  • 编写故障恢复流程
  • 编写备份和恢复步骤

🎯 第二阶段:后端开发(第 2 周)

🔴 P0 任务:核心后端功能

2.1 Server 基础配置(精简版)

  • 创建 src/server.ts 主文件
  • 配置 Express 应用
    app.use(cors({ origin: process.env.FRONTEND_URL }));
    app.use(express.json({ limit: '10mb' }));
    app.use(compression()); // 启用 Gzip
    
  • 配置错误处理中间件
  • 实现健康检查端点 GET /health
  • 配置日志(使用 Pino性能优于 Winston

2.2 数据库配置(针对单机)

  • 创建 PostgreSQL 容器配置
    postgres:
      image: postgres:15-alpine  # 使用 Alpine 减少镜像大小
      environment:
        POSTGRES_DB: jiao77_db
        POSTGRES_USER: app
        POSTGRES_PASSWORD: ${DB_PASSWORD}
      volumes:
        - postgres_data:/var/lib/postgresql/data
      restart: always
    
  • 创建连接池配置
    new Pool({
      max: 20,  // 单机限制连接数
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 2000,
    })
    
  • 实现连接池监控函数

2.3 数据库 Schema优化版

  • 创建 SQL 初始化脚本
    -- 评论表(带分区考虑)
    CREATE TABLE comments (
      id SERIAL PRIMARY KEY,
      report_id VARCHAR(100) NOT NULL,
      author VARCHAR(100) NOT NULL,
      content TEXT NOT NULL CHECK (char_length(content) <= 5000),
      status VARCHAR(20) DEFAULT 'pending',
      created_at TIMESTAMP DEFAULT NOW(),
      updated_at TIMESTAMP DEFAULT NOW()
    );
    
    -- 索引优化
    CREATE INDEX CONCURRENTLY idx_comments_report_id 
      ON comments(report_id, created_at DESC);
    CREATE INDEX CONCURRENTLY idx_comments_status 
      ON comments(status, created_at DESC);
    
    -- 统计表
    CREATE TABLE report_stats (
      id SERIAL PRIMARY KEY,
      report_id VARCHAR(100) UNIQUE NOT NULL,
      views INTEGER DEFAULT 0,
      comments INTEGER DEFAULT 0,
      likes INTEGER DEFAULT 0,
      shares INTEGER DEFAULT 0,
      last_updated TIMESTAMP DEFAULT NOW()
    );
    
    -- 点赞表
    CREATE TABLE likes (
      id SERIAL PRIMARY KEY,
      report_id VARCHAR(100) NOT NULL,
      client_id VARCHAR(100) NOT NULL,
      created_at TIMESTAMP DEFAULT NOW(),
      UNIQUE(report_id, client_id)
    );
    
  • 创建数据库初始化脚本 scripts/db-init.sql
  • 准备数据库迁移工具(简单的 SQL 文件版本控制)

2.4 评论 API 实现(轻量级)

  • GET /api/comments?reportId=xxx&page=1&limit=20 - 分页获取
  • POST /api/comments - 创建评论(含速率限制)
  • DELETE /api/comments/:id - 删除评论(仅作者或管理员)
  • 实现数据验证(使用 Zod
  • 实现错误处理

2.5 统计 API 实现(轻量级)

  • GET /api/stats/:reportId - 获取统计数据(加缓存)
  • POST /api/stats/:reportId/view - 记录浏览(批量处理)
  • POST /api/stats/:reportId/like - 点赞
  • 实现请求去重(基于 IP + clientId
  • 实现缓存策略

2.6 中间件实现(安全 + 性能)

  • 速率限制中间件
    const rateLimit = require('express-rate-limit');
    const limiter = rateLimit({
      windowMs: 15 * 60 * 1000,  // 15 分钟
      max: 100,  // 单机限制请求数
      keyGenerator: (req) => req.ip,
      skip: (req) => req.path === '/health'
    });
    
  • 请求日志中间件Pino
  • 数据验证中间件Zod
  • 错误处理中间件

2.7 本地测试

  • 运行 npm run dev 本地启动
  • 测试各个 API 端点
  • 测试数据库连接
  • 验证错误处理

🟠 P1 任务:后端测试

2.8 单元测试(简化版)

  • 编写 API 端点测试
  • 编写数据验证测试
  • 编写错误处理测试
  • 目标覆盖率 > 70%(单机优先功能质量)

2.9 集成测试

  • 测试完整的评论流程
  • 测试完整的统计流程
  • 测试异常场景

🎯 第三阶段:前端开发(第 2-3 周)

🔴 P0 任务:前端集成

3.1 Astro 混合渲染配置

  • 更新 astro.config.mjs
    export default defineConfig({
      integrations: [react(), tailwind()],
      output: 'hybrid',
      adapter: node({ mode: 'standalone' }),
      vite: {
        ssr: { external: ['pg'] }
      }
    });
    
  • 本地测试混合渲染

3.2 API 客户端库

  • 创建 src/lib/api-client.ts
    const API_BASE = process.env.PUBLIC_API_URL || 'http://localhost:3000';
    
    export async function fetchAPI(
      path: string,
      options?: RequestInit
    ) {
      const response = await fetch(`${API_BASE}${path}`, {
        headers: {
          'Content-Type': 'application/json',
          ...options?.headers,
        },
        ...options,
      });
    
      if (!response.ok) {
        throw new Error(`API Error: ${response.status}`);
      }
      return response.json();
    }
    
  • 实现缓存策略

3.3 React 组件开发(轻量级)

  • 开发 CommentSection 组件
    export default function CommentSection({ 
      reportId 
    }: { 
      reportId: string 
    }) {
      const [comments, setComments] = useState<Comment[]>([]);
      const [loading, setLoading] = useState(false);
    
      useEffect(() => {
        setLoading(true);
        fetchAPI(`/api/comments?reportId=${reportId}`)
          .then(setComments)
          .finally(() => setLoading(false));
      }, [reportId]);
    
      // ... 组件逻辑
    }
    
  • 开发 StatsPanel 组件(简化版)
    export default function StatsPanel({ reportId }: { reportId: string }) {
      const [stats, setStats] = useState<Stats | null>(null);
    
      useEffect(() => {
        fetchAPI(`/api/stats/${reportId}`).then(setStats);
      }, [reportId]);
    
      if (!stats) return <Skeleton />;
    
      return (
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
          <StatCard label="浏览" value={stats.views} />
          <StatCard label="评论" value={stats.comments} />
          <StatCard label="点赞" value={stats.likes} />
          <StatCard label="分享" value={stats.shares} />
        </div>
      );
    }
    
  • 开发 LikeButton 组件

3.4 页面集成

  • 在报告页面导入组件
  • 设置客户端加载指令
  • 样式适配

🟠 P1 任务:前端测试

3.5 组件测试

  • 编写简单的组件测试Vitest
  • 测试数据加载
  • 测试用户交互

🎯 第四阶段:单机容器化部署(第 3 周)

🔴 P0 任务Docker 化应用

4.1 后端 DockerfileAlpine 优化)

  • 创建 backend/Dockerfile
    # 构建阶段
    FROM node:18-alpine AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci --only=production && npm cache clean --force
    
    # 运行阶段
    FROM node:18-alpine
    WORKDIR /app
    RUN apk add --no-cache dumb-init
    
    COPY --from=builder /app/node_modules ./node_modules
    COPY . .
    
    EXPOSE 3000
    ENTRYPOINT ["dumb-init", "--"]
    CMD ["node", "dist/server.js"]
    
  • 镜像大小目标:< 200MB

4.2 前端 Dockerfile静态优化

  • 创建 frontend/Dockerfile
    FROM node:18-alpine AS builder
    WORKDIR /app
    COPY package*.json ./
    RUN npm ci
    COPY . .
    RUN npm run build
    
    FROM node:18-alpine
    WORKDIR /app
    COPY --from=builder /app/dist ./dist
    EXPOSE 3000
    CMD ["node", "./dist/server/entry.mjs"]
    

4.3 Docker Compose 配置(单机专用)

  • 创建 docker-compose.yml
    version: '3.8'
    
    services:
      postgres:
        image: postgres:15-alpine
        container_name: jiao77_postgres
        environment:
          POSTGRES_DB: ${DB_NAME}
          POSTGRES_USER: ${DB_USER}
          POSTGRES_PASSWORD: ${DB_PASSWORD}
        volumes:
          - postgres_data:/var/lib/postgresql/data
          - ./scripts/db-init.sql:/docker-entrypoint-initdb.d/init.sql
        restart: unless-stopped
        # 资源限制
        deploy:
          resources:
            limits:
              cpus: '1'
              memory: 1G
            reservations:
              cpus: '0.5'
              memory: 512M
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
          interval: 10s
          timeout: 5s
          retries: 5
    
      redis:
        image: redis:7-alpine
        container_name: jiao77_redis
        restart: unless-stopped
        deploy:
          resources:
            limits:
              cpus: '0.5'
              memory: 512M
        volumes:
          - redis_data:/data
    
      api:
        build:
          context: ./backend
          dockerfile: Dockerfile
        container_name: jiao77_api
        depends_on:
          postgres:
            condition: service_healthy
          redis:
            condition: service_started
        environment:
          NODE_ENV: production
          DATABASE_URL: postgresql://${DB_USER}:${DB_PASSWORD}@postgres:5432/${DB_NAME}
          REDIS_URL: redis://redis:6379
          PORT: 3000
        ports:
          - "3000:3000"
        restart: unless-stopped
        deploy:
          resources:
            limits:
              cpus: '1'
              memory: 1G
            reservations:
              cpus: '0.5'
              memory: 512M
        healthcheck:
          test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
          interval: 30s
          timeout: 10s
          retries: 3
    
      web:
        build:
          context: ./frontend
          dockerfile: Dockerfile
        container_name: jiao77_web
        depends_on:
          - api
        environment:
          PUBLIC_API_URL: http://api:3000
        ports:
          - "3001:3000"
        restart: unless-stopped
        deploy:
          resources:
            limits:
              cpus: '0.5'
              memory: 512M
    
      nginx:
        image: nginx:alpine
        container_name: jiao77_nginx
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf:ro
          - ./ssl:/etc/nginx/ssl:ro
          - nginx_cache:/var/cache/nginx
        depends_on:
          - web
          - api
        restart: unless-stopped
        deploy:
          resources:
            limits:
              cpus: '0.5'
              memory: 256M
    
    volumes:
      postgres_data:
      redis_data:
      nginx_cache:
    
  • 本地测试 Docker Compose

4.4 Nginx 配置(单机反向代理)

  • 创建 nginx.conf
    user nginx;
    worker_processes auto;
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;
    
    events {
      worker_connections 2048;
      use epoll;
    }
    
    http {
      include /etc/nginx/mime.types;
      default_type application/octet-stream;
    
      # 性能优化
      sendfile on;
      tcp_nopush on;
      tcp_nodelay on;
      keepalive_timeout 65;
    
      # 日志格式
      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;
    
      # 缓存配置
      proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=http_cache:10m 
                       max_size=1g inactive=60m use_temp_path=off;
    
      gzip on;
      gzip_vary on;
      gzip_proxied any;
      gzip_comp_level 6;
      gzip_types text/plain text/css text/xml text/javascript 
                 application/json application/javascript application/xml+rss;
    
      upstream api {
        server api:3000;
      }
    
      upstream web {
        server web:3000;
      }
    
      server {
        listen 80;
        server_name _;
        return 301 https://$host$request_uri;
      }
    
      server {
        listen 443 ssl http2;
        server_name jiao77.cn www.jiao77.cn;
    
        ssl_certificate /etc/nginx/ssl/cert.pem;
        ssl_certificate_key /etc/nginx/ssl/key.pem;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers HIGH:!aNULL:!MD5;
    
        # 静态文件
        location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff|woff2)$ {
          proxy_pass http://web;
          proxy_cache http_cache;
          proxy_cache_valid 200 30d;
          expires 30d;
          add_header Cache-Control "public, immutable";
        }
    
        # API 接口
        location /api/ {
          proxy_pass http://api;
          proxy_cache http_cache;
          proxy_cache_valid 200 10m;
          proxy_cache_key "$scheme$request_method$host$request_uri";
          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;
        }
    
        # 健康检查
        location /health {
          access_log off;
          proxy_pass http://api;
        }
    
        # 前端
        location / {
          proxy_pass http://web;
          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;
        }
      }
    }
    

4.5 环境配置

  • 创建 .env 模板
    NODE_ENV=production
    
    # 数据库
    DB_NAME=jiao77_db
    DB_USER=app
    DB_PASSWORD=<strong-password>
    
    # Redis
    REDIS_URL=redis://redis:6379
    
    # 应用
    PORT=3000
    FRONTEND_URL=https://jiao77.cn
    API_BASE=https://jiao77.cn/api
    
    # 日志
    LOG_LEVEL=info
    

4.6 启动脚本

  • 创建 scripts/start.sh
    #!/bin/bash
    set -e
    
    echo "🚀 启动应用..."
    
    # 拉取最新代码
    git pull origin main
    
    # 构建镜像
    docker-compose build --no-cache
    
    # 启动服务
    docker-compose up -d
    
    # 等待数据库启动
    sleep 10
    
    # 运行数据库迁移
    docker-compose exec -T api npm run migrate
    
    # 健康检查
    echo "✅ 等待服务健康..."
    for i in {1..30}; do
      if curl -f http://localhost:3000/health > /dev/null 2>&1; then
        echo "✅ 应用已启动"
        exit 0
      fi
      echo "⏳ 尝试 $i/30..."
      sleep 1
    done
    
    echo "❌ 启动失败"
    exit 1
    
  • 创建 scripts/stop.sh - 优雅关闭
  • 创建 scripts/backup.sh - 数据备份

🟠 P1 任务:性能优化

4.7 数据库优化(单机)

  • 优化 PostgreSQL 配置
    environment:
      POSTGRES_INITDB_ARGS: |
        -c shared_buffers=256MB
        -c effective_cache_size=1GB
        -c maintenance_work_mem=64MB
        -c work_mem=16MB
    
  • 创建必要的数据库索引
  • 配置连接池大小

4.8 API 性能优化

  • 实现 API 分页20 条/页)
  • 实现查询结果缓存Redis
  • 实现请求压缩Gzip
  • 实现 HTTP 缓存头

4.9 前端性能优化

  • Astro 静态生成优化
  • 图片优化和懒加载
  • 代码分割
  • 浏览器缓存配置

🎯 第五阶段:监控与备份(第 4 周)

🔴 P0 任务:核心监控

5.1 应用健康监控

  • 配置 /health 端点
  • 配置 /metrics 端点Prometheus 格式)
  • 编写简单的监控脚本
    #!/bin/bash
    # 定期检查服务状态
    curl -f http://localhost:3000/health || {
      echo "❌ API 宕机" | mail -s "告警" admin@jiao77.cn
      docker-compose restart api
    }
    

5.2 数据库监控

  • 监控数据库连接数
  • 监控磁盘使用率
  • 监控查询缓慢日志

5.3 系统监控

  • 监控 CPU 使用率(< 70%
  • 监控内存使用率(< 80%
  • 监控磁盘使用率(< 80%
  • 配置告警规则

5.4 日志管理

  • 配置 Docker 日志驱动json-file + 轮转)
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
    
  • 实现日志聚合可选ELK Stack 精简版)

🔴 P0 任务:备份策略

5.5 数据库备份

  • 创建自动备份脚本
    #!/bin/bash
    BACKUP_DIR="/backup/postgresql"
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    
    docker-compose exec -T postgres pg_dump \
      -U app jiao77_db | gzip > $BACKUP_DIR/backup_$TIMESTAMP.sql.gz
    
    # 保留最近 7 天的备份
    find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +7 -delete
    
  • 配置每日凌晨 2 点自动备份crontab
  • 测试备份恢复流程

5.6 应用备份

  • 备份应用代码Git
  • 备份配置文件
  • 备份日志文件(定期轮转)

5.7 存储规划

  • 本地备份30GB7 天备份)
  • 云存储备份20GB使用 Aliyun OSS 或 COS
  • 监控备份完成状态

🟠 P1 任务:故障恢复

5.8 故障恢复流程

  • 编写数据库恢复脚本
    #!/bin/bash
    # 恢复数据库
    docker-compose exec -T postgres psql -U app jiao77_db < backup.sql
    
  • 编写服务重启脚本
  • 编写完整的应急响应手册

5.9 测试和演练

  • 测试备份恢复(月度)
  • 测试服务重启(周度)
  • 演练故障场景(季度)

🎯 第六阶段:上线和运维(第 5 周)

🔴 P0 任务:上线前准备

6.1 最终检查清单

  • 所有功能测试通过
  • 性能基线建立
  • 安全审计完成
  • 备份策略验证
  • 文档完备
  • 监控告警配置
  • 回滚计划准备

6.2 SSL 证书配置

  • 使用 Certbot 申请证书
    sudo certbot certonly --standalone -d jiao77.cn -d www.jiao77.cn
    
  • 配置自动续期
    sudo systemctl enable certbot.timer
    
  • 配置 Nginx 使用证书

6.3 域名配置

  • 配置 A 记录指向公网 IP
  • 配置 CNAMEwww
  • 配置 MX 记录(邮件,可选)
  • 测试 DNS 解析

6.4 上线检查

  • SSH 配置(禁用密码登录)
  • 防火墙规则验证
  • 资源使用率基线
  • 日志系统就位

🔴 P0 任务:正式部署

6.5 发布到 VPS

  • 登录 VPS
  • 执行部署脚本:bash scripts/start.sh
  • 验证所有服务正常运行
  • 验证 HTTPS 连接
  • 验证所有功能可用

6.6 上线后验证

  • 访问前端页面
  • 测试评论功能
  • 测试统计功能
  • 检查日志无错误

6.7 持续监控(上线后 24h

  • 监控 CPU、内存、磁盘
  • 监控应用日志
  • 监控用户反馈
  • 记录性能数据

🟠 P1 任务:运维自动化

6.8 Cron 任务设置

  • 每日 02:00 - 数据库备份
  • 每周日 03:00 - 系统备份
  • 每小时 - 健康检查
  • 每 10 分钟 - 监控检查

6.9 日常运维任务

  • 周度备份验证
  • 月度性能分析
  • 季度灾难恢复演练
  • 定期安全更新

6.10 长期维护计划

  • Docker 镜像定期更新
  • 依赖包定期更新
  • PostgreSQL 大版本升级计划
  • 磁盘空间管理计划

🟠 P1 任务:文档和培训

6.11 运维文档

  • 部署操作手册
  • 故障排查指南
  • 备份恢复流程
  • 监控告警规则

6.12 应急响应

  • 编写应急响应计划
  • 列出主要故障场景
  • 编写恢复步骤

🎯 可选优化P2 任务)

🟡 P2 任务:性能优化

7.1 查询优化

  • 数据库慢查询分析
  • 添加查询索引
  • 优化 N+1 查询
  • 实现查询结果缓存

7.2 缓存优化

  • Redis 缓存热数据
  • 实现缓存预热
  • 实现缓存失效策略

7.3 API 优化

  • 减少 API 响应大小
  • 实现字段选择
  • 实现 API 聚合

🎯 后续扩展P3 任务)

🟢 P3 任务:功能扩展

8.1 用户系统

  • 用户认证
  • 用户资料
  • 权限管理

8.2 社区功能

  • 评论回复
  • 用户关注
  • 排行榜

8.3 数据分析

  • 用户行为分析
  • 内容热力分析

📊 单机配置资源预算

VPS 规格建议

配置4核 CPU、8GB 内存、100GB SSD
操作系统Ubuntu 20.04 LTS
带宽:大带宽(>10 Mbps

容器资源分配

PostgreSQL
  - CPU limit: 1 核
  - Memory limit: 1GB
  - 实际使用0.5 核、500MB

Redis
  - CPU limit: 0.5 核
  - Memory limit: 512MB
  - 实际使用0.2 核、256MB

API (Node.js)
  - CPU limit: 1 核
  - Memory limit: 1GB
  - 实际使用0.3 核、300MB

Web (Astro)
  - CPU limit: 0.5 核
  - Memory limit: 512MB
  - 实际使用0.1 核、100MB

Nginx
  - CPU limit: 0.5 核
  - Memory limit: 256MB
  - 实际使用0.05 核、50MB

总计峰值3 核、3.5GB
实际使用1.15 核、1.2GB(预留安全边际)

存储分配100GB

系统和 Docker20GB
PostgreSQL 数据30GB
Redis 数据2GB
应用代码5GB
日志文件3GB
备份文件30GB
缓冲区10GB

⏱️ 时间表(针对单机优化)

第1周 - VPS 准备 + 后端开发  60 小时
第2周 - 前端开发 + 集成      50 小时
第3周 - Docker 化 + 部署      40 小时
第4周 - 监控 + 备份 + 测试    40 小时
第5周 - 上线 + 优化           30 小时
──────────────────────────────────
总计220 小时 ≈ 5-6 周(单人开发)
     ≈ 3-4 周(双人开发)

🚀 快速开始指南

立即开始(第 1 天)

# 1. SSH 登录 VPS
ssh root@<ip>

# 2. 安装 Docker 和 Compose
curl -fsSL https://get.docker.com | sh
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 3. 克隆项目
git clone <repo> /home/app

# 4. 配置环境
cd /home/app
cp .env.example .env
# 编辑 .env配置数据库密码等

# 5. 启动应用
docker-compose up -d

# 6. 验证
curl http://localhost:3000/health

配置 SSL第 2 天)

# 使用 Certbot
sudo apt install certbot
sudo certbot certonly --standalone -d jiao77.cn -d www.jiao77.cn

# 在 docker-compose.yml 中配置证书路径
# 重启 Nginx
docker-compose restart nginx

配置备份(第 3 天)

# 添加 cron 任务
crontab -e

# 添加备份命令
0 2 * * * cd /home/app && bash scripts/backup.sh

💡 单机部署最佳实践

DO应该做

  • 定期备份数据库
  • 监控资源使用率
  • 设置告警规则
  • 使用 Alpine 镜像减少内存
  • 配置资源限制
  • 日志轮转
  • 定期更新依赖

DON'T不应该做

  • 不使用 root 运行容器
  • 不在生产用开发镜像
  • 不忽视监控告警
  • 不手动管理依赖版本
  • 不连续部署到生产(需要测试)

🔧 常见问题排查

问题 1内存不足

# 检查内存使用
docker stats

# 解决方案:
# 1. 减少 PostgreSQL 缓冲区
# 2. 减少 Redis 最大内存
# 3. 优化 Node.js 堆大小

问题 2磁盘满

# 检查磁盘
df -h

# 清理 Docker 镜像
docker image prune -a

# 清理 Docker 容器
docker container prune

问题 3性能下降

# 检查慢查询
docker-compose logs api | grep "SLOW"

# 检查数据库连接
docker-compose exec postgres psql -c "SELECT count(*) FROM pg_stat_activity;"

📈 性能指标目标

指标 目标 说明
页面加载时间 < 2s 首次加载
API 响应时间 < 200ms 平均响应
数据库查询 < 100ms 95 分位
CPU 使用率 < 60% 平均
内存使用率 < 75% 峰值
磁盘使用率 < 80% 实时
可用性 99.5% 月度

🎯 总结

这个方案针对单机 VPS 环境进行了全面优化:

  1. 资源优化 - 使用 Alpine 镜像、资源限制、连接池优化
  2. 部署简化 - Docker Compose 单文件部署、Nginx 反向代理
  3. 监控自动化 - 健康检查、告警规则、自动重启
  4. 备份完善 - 每日备份、7 天保留、恢复流程
  5. 成本低 - 无需复杂基础设施、单机成本 ~¥100/月

建议:从 P0 任务开始,按阶段稳步推进,确保每个阶段的质量。