Files
Nexus/docs/reports/review-deploy-architecture-2026-05-21.md
T
Your Name c9a99f4fb3 fix: 全项目文档对齐 + 代码清理
代码修复:
- web/agent/agent.py: datetime.utcnow() → datetime.now(timezone.utc)
- requirements.txt: 移除 paramiko==3.5.0 (已无活跃引用)
- 删除 server/infrastructure/ssh/pool.py (DEPRECATED, 无引用)

连接池三层对齐 (config.py/.env.example/session.py):
- DB_POOL_SIZE 100→160, DB_MAX_OVERFLOW 100→120
- 基于 MySQL max_connections=400, install.php 公式

文档修复 (21项):
- P0: 硬编码域名/IP替换为配置变量占位符
- P1: 10个过时设计文档加归档标注 (引用旧文件结构)
- P2: step-3-webssh报告 paramiko引用修正
- 6份审查报告连接池参数勘误 100/100→160/120
- ECC安全报告 EC5 datetime.utcnow 标记已修复
- docs/README.md 文档索引重写
- docs/memory/mem_nexus_overview.md 移除硬编码凭证
- docs/project/tech-stack-inventory.md paramiko标记已移除

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 08:19:56 +08:00

18 KiB
Raw Blame History

运维总监审查报告

项目: Nexus 6.0 — 服务器运维管理平台 审查时间: 2026-05-212026-05-22 勘误更新) 审查范围: deploy/ 全部配置、docs/project/deploy.md 部署指南、server/config.py 配置项、server/main.py 启动配置、server/background/ 后台任务、server/infrastructure/ 基础设施层

勘误说明 (2026-05-22): 本报告部分问题在审查后已修复,已在相应位置标注 已修复。 审查人: 运维总监


1. 部署架构总览

                         ┌──────────────┐
                         │   Let's Encrypt │  (生产环境 HTTPS)
                         │   (宝塔面板)    │
                         └──────┬───────┘
                                │
                         ┌──────▼───────┐
                         │    Nginx     │  ← 反向代理 + 静态文件 + PHP-FPM
                         │  (80/443)    │
                         └──┬───────┬──┘
                            │       │
              ┌─────────────▼┐  ┌───▼──────────┐
              │  FastAPI     │  │  PHP-FPM     │
              │  :8600       │  │  (旧前端)    │
              │  (4 workers) │  │              │
              └──┬───────┬───┘  └──────────────┘
                 │       │
          ┌──────▼──┐ ┌──▼──────────┐
          │  Redis  │ │  MySQL 8.4  │
          │  (实时)  │ │  (历史)     │
          └─────────┘ └─────────────┘

3层守护机制:
  Layer 1: Supervisor ─── Python崩溃 → 自动重启
  Layer 2: self_monitor ── 30s检查Redis/MySQL/WS → Telegram告警
  Layer 3: health_monitor ── 1min HTTP GET /health → 连续3次失败 → restart + Telegram

整体评价: 架构设计合理,三层守护覆盖全面,数据流清晰(Agent → Redis → 前端直读 → 10min → MySQL)。核心问题在于配置一致性偏差资源预留过大安全防护薄弱


2. Supervisor配置评估

文件: deploy/nexus.conf

优点

  • autorestart=true + startretries=10 — 崩溃自动重启,最多重试10次
  • stopsignal=INT — SIGINT发送给uvicorn,可实现优雅关闭
  • stopwaitsecs=10 — 给进程10秒处理完当前请求
  • 日志自动轮转:50MB切割,保留5个备份
  • 不硬编码密钥(依赖.env文件)— 安全合规

问题

严重度 问题 说明
单Worker运行 (--workers 缺失) nexus.conf 只用1个worker,但文档 deploy.md 的示例配置写着 --workers 4。两者不一致。实际线上用1个worker处理所有请求(包括心跳、WebSocket、API),单点过载风险。详见第8节。
startsecs=3 偏短 如果应用启动耗时超过3秒(如数据库表较多时init_db可能较慢),Supervisor会误判为启动失败。建议改为 startsecs=10
user=root 运行 Python进程以root权限运行。如果FastAPI出现RCE漏洞,攻击者可获得服务器完全控制权。建议创建专用系统用户 nexus
缺少 redirect_stderr=true 当前将stderr和stdout分别写入两个文件。设为 redirect_stderr=true 可统一日志管理
environment 变量 虽然依赖.env文件启动,但指定 PYTHONPATH 环境变量可以避免潜在的导入路径问题

建议修复

[program:nexus]
command=/www/wwwroot/api.synaglobal.vip/venv/bin/uvicorn server.main:app --host 0.0.0.0 --port 8600 --workers 4
directory=/www/wwwroot/api.synaglobal.vip
user=nexus                          # 改为专用系统用户
autostart=true
autorestart=true
startretries=10
startsecs=10                        # 加长启动验证时间
stopwaitsecs=20                     # 加长优雅关闭等待
stopsignal=INT
environment=
    PATH="/www/wwwroot/api.synaglobal.vip/venv/bin:%(ENV_PATH)s",
    PYTHONPATH="/www/wwwroot/api.synaglobal.vip:%(ENV_PATH)s"
redirect_stderr=true
stdout_logfile=/var/log/nexus/nexus.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=5

3. Nginx配置评估

文件: deploy/nginx_172.31.170.47.confWSL环境)

优点

  • upstream nexus_api { keepalive 32; } — 使用连接池,减少TCP握手开销
  • 清晰的全域名/API/WebSocket/静态文件分离路由
  • 敏感文件保护:location ~ /\. { deny all; } + location ~ /data/config\.php$ { deny all; }
  • 静态资源7天缓存:expires 7d; add_header Cache-Control "public, immutable";
  • WebSocket代理配置正确:Upgrade / Connection 头、proxy_read_timeout 180s
  • client_max_body_size 100m — 适合文件管理功能

问题

严重度 问题 说明
无HTTPS配置 WSL环境的Nginx配置只有HTTP 80。对于运维管理平台,即使在WSL内网也应启用HTTPS。至少应配置自签名证书。
无安全响应头 缺少 X-Content-Type-OptionsX-Frame-OptionsContent-Security-PolicyStrict-Transport-Security 等关键安全头
无速率限制 API端点和登录接口缺少 limit_req 配置,存在暴力破解和DDoS风险
无请求体大小限制 API代理未设置 client_max_body_size,但全局设置了100m,而API代理不应允许这么大的请求体
location /health 缺少转发头 健康检查代理未设置 X-Real-IP 等头信息(虽然对健康检查影响不大,但不一致)
无压缩配置 未启用gzip/brotli压缩,JSON API响应可能浪费带宽
无日志格式自定义 使用默认Combined格式,缺少上游响应时间等关键指标
WSL配置和生产配置分离 存在两份Nginx配置(WSL + 生产),但生产配置在deploy.md中而非独立文件

生产环境安全头建议(补充到Nginx配置)

# 在 server block 中添加
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# API速率限制
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
location /api/ {
    limit_req zone=api burst=50 nodelay;
    # ... 现有配置
}

# 登录接口限制(更严格)
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/s;
location /api/auth/ {
    limit_req zone=login burst=10 nodelay;
    # ...
}

4. 三层守护机制评估

4.1 Layer 1: Supervisor

维度 评估 说明
崩溃检测 进程退出时,Supervisor即时感知
自动重启 autorestart=true + startretries=10
优雅关闭 SIGINT + 10秒等待
启动验证 ⚠️ startsecs=3 可能偏短,建议10秒
频繁崩溃防护 ⚠️ 10次重试后停止,但未配置 startretryinterval(默认0=无间隔),可能瞬间耗尽重试次数

4.2 Layer 2: Python self_monitor

维度 评估 说明
检查间隔 每30秒
Redis检测 返回None时告警
MySQL检测 执行SELECT 1
WebSocket清理 移除过期客户端
自动修复 仅发送Telegram告警,不做任何修复操作
连续失败降级 无降级逻辑,每次失败都发告警(可能造成告警轰炸)

严重问题: Layer 2只有"检测+告警"能力,没有任何自动修复动作。例如Redis连接丢失后,self_monitor只是发一条Telegram消息,不做重连尝试。虽然 get_redis() 函数在检测到连接丢失后会置 _redis_pool = None,下次调用会尝试重连,但self_monitor自身的Redis检测逻辑并未利用这个机制重连以提高成功率。

4.3 Layer 3: Shell health_monitor.sh

维度 评估 说明
独立性 纯Shell脚本,不依赖Python
连续失败阈值 3次连续失败才触发重启
重启后验证 restart后sleep 5秒,再验证
Telegram通知 失败/恢复/人工介入三类通知
配置来源 从config.php或.env读取Telegram凭证

严重问题: 循环重启风暴风险。当连续3次失败后,脚本调用 supervisorctl restart,如果重启后验证仍然失败,不会重置FAIL计数器。这意味着每次cron执行都会再次触发 supervisorctl restart(因为FAIL计数器保持在3+)。这会造成每分钟一次的循环重启风暴。正确的做法应该是增加"冷却期"机制——例如连续N次重启失败后,停止自动重启并仅发送人类介入通知。

4.4 三层联动评估

场景: Python进程崩溃
  Layer 1: Supervisor 即时检测 → 秒级重启 ✓
  Layer 2: 如果Python在30s内恢复,self_monitor不会触发告警 ✓
  Layer 3: 如果1分钟内恢复,health_monitor不会触发(FAIL计数器不会达到3)✓

场景: Python进程僵死(不崩溃但无响应)
  Layer 1: 进程未退出,Supervisor不触发 ✗
  Layer 2: self_monitor只要asyncio事件循环还能运行就能检测,但如果整个进程僵死则不行 ✗
  Layer 3: HTTP GET /health超时,3次后触发supervisorctl restart ✓

场景: Redis宕机
  Layer 1: 不触发(Python进程正常运行)✓
  Layer 2: 30s内检测到Redis丢失,发Telegram告警(但不尝试修复)⚠️
  Layer 3: 不触发(/health端点仍能响应,只是标记redis=unavailable)✓(正确)

场景: MySQL连接池耗尽
  Layer 1: 不触发 ✓
  Layer 2: 30s内检测到MySQL异常,发Telegram告警 ⚠️
  Layer 3: 不触发(HTTP健康检查返回python=ok)✓(正确)

评估: 三层守护的覆盖域合理,各层分工明确。核心缺失是 Layer 2 缺乏自动修复能力。循环重启风暴是需要优先修复的风险。


5. 运维风险点

5.1 高风险

# 风险 影响 建议
R1 单Worker生产运行 一个worker处理所有WebSocket连接、心跳接收、API请求。一旦某个请求阻塞(如慢查询),所有其他请求(包括心跳)都会排队等待。后果:Agent心跳超时、WebSocket断连、健康检查失败触发误重启。 使用 --workers 4 并启用 --ws max_size=16 等uvicorn优化参数
R2 循环重启风暴 health_monitor在连续3次失败后,每分钟执行一次 supervisorctl restart,无论重启是否成功。如果根本原因(如配置错误、端口冲突)未解决,会造成每分钟的反复重启循环。 增加冷却期:连续N次重启失败后,停止自动重启,仅发送"需人工介入"告警,等待操作员处理
R3 Root运行所有进程 Supervisor配置 user=root,Python进程以root身份运行。如果FastAPI存在任意代码执行漏洞(如依赖库CVE),攻击者可获得服务器完全控制权。 创建 nexus 系统用户,最小权限原则
R4 CORS全开放 allow_origins=["*"] 已修复 — 改为 settings.CORS_ORIGINS.split(",")NEXUS_CORS_ORIGINS 环境变量读取白名单

5.2 中风险

# 风险 影响 建议
R5 数据库连接池监控 DB_POOL_SIZE=100 + DB_MAX_OVERFLOW=100 → 已修正为 DB_POOL_SIZE=160 + DB_MAX_OVERFLOW=120(基于 MySQL max_connections=400)。install.php 已实现自动计算:poolSize = max(20, maxConn * 0.4) install.php 自动计算已落地。建议增加运行时连接池使用率监控告警
R6 健康检查端口固定 HEALTH_URL 硬编码为 http://127.0.0.1:8600/health,如果后续端口变更需同时修改脚本。 改为从配置文件读取或作为脚本参数传入
R7 异常处理宽泛 load_settings_from_dbexcept Exception 静默吞掉所有异常,返回0。如果settings表结构变更或数据类型异常,不会被及时发现。 区分可忽略异常和需要告警的异常,对关键错误发送运维告警
R8 无日志集中管理 Supervisor日志写在 /var/log/nexus/Nginx日志在 /www/wwwlogs/Python日志可能分散到stdout。无统一日志中心,故障排查需要手动查看多个位置。 使用 systemd-journald 或 rsyslog 统一收集,考虑接入 ELK/Loki
R9 文档与配置不一致 deploy.md 中Nexus Supervisor配置示例使用 --workers 4startretries, startsecs 等未列出。实际 nexus.conf 只有单worker。部署新环境时可能按文档配置4 workers,但本地nexus.conf是1 worker。 同步文档和实际配置,确保部署指南与部署文件一致
R10 无数据库备份策略 项目中未找到自动备份脚本或策略。MySQL存储心跳历史、告警配置、服务器信息,一旦数据丢失将造成严重后果。 实现 mysqldumpXtraBackup 每日备份 + 7天轮转

5.3 低风险

# 风险 影响 建议
R11 无监控面板 无Grafana/Prometheus等可视化监控 接入node_exporter + Prometheus
R12 无容量规划 心跳数据量增长后MySQL性能未知 在1000+服务器规模下进行压测
R13 WSL无HTTPS 管理流量明文传输 至少配置自签名证书
R14 缺少staging环境 变更直接上生产 保持WSL作为staging环境

6. 改进建议

P0 — 立即修复(影响生产稳定性)

  1. Supervisor启用多Worker

    # nexus.conf 中 command 添加 --workers 4
    command=/www/wwwroot/api.synaglobal.vip/venv/bin/uvicorn server.main:app --host 0.0.0.0 --port 8600 --workers 4
    

    注意: 多Worker下WebSocket连接会分配给不同进程,需要使用Redis Pub/Sub做跨进程WebSocket广播。如果当前WebSocket实现(connected_clients 是内存集合)不支持跨进程,则需评估。推荐启用 --ws ping_interval 20

  2. health_monitor.sh 增加重启冷却

    # 在重启失败后增加冷却文件
    COOLDOWN_FILE="/tmp/nexus_restart_cooldown"
    COOLDOWN_PERIOD=10  # 10分钟内不再自动重启
    
    # 在重启失败分支中
    if [ "$FAIL" -ge "$MAX_FAIL" ]; then
        # 检查冷却期
        COOLDOWN=$(cat "$COOLDOWN_FILE" 2>/dev/null || echo "0")
        NOW=$(date +%s)
        if [ "$COOLDOWN" -gt "$NOW" ]; then
            send_telegram "⚠️ Nexus重启冷却中(跳过自动重启)"
            exit 0
        fi
        # ... 执行重启 ...
        # 如果重启失败,设置10分钟冷却
        echo "$((NOW + COOLDOWN_PERIOD * 60))" > "$COOLDOWN_FILE"
    fi
    
  3. 创建专用服务用户

    sudo useradd -r -s /usr/sbin/nologin -M nexus
    sudo chown -R nexus:nexus /www/wwwroot/api.synaglobal.vip
    sudo chmod 640 /www/wwwroot/api.synaglobal.vip/.env  # 限制.env访问
    

P1 — 短期改进(本周内)

  1. 调优数据库连接池 → 已修正:config.py 默认值已调整为 DB_POOL_SIZE=160 + DB_MAX_OVERFLOW=120(基于 MySQL max_connections=400)。install.php 自动计算逻辑在生产环境会覆盖 .env 值。

  2. Nginx增加安全头和生产配置文件

    • deploy.md 中提取生产Nginx配置为独立文件 deploy/nginx_production.conf
    • 增加安全响应头、速率限制
  3. self_monitor增加自动修复逻辑

    • Redis丢失时:主动调用 get_redis() 触发重连(现有代码已支持,但需确保self_monitor层面触发)
    # Redis check — 主动触发重连
    redis = await get_redis()
    if redis is None and settings.REDIS_URL:
        await send_telegram_system_alert("⚠️ Redis连接丢失,正在尝试重连...")
        _redis_pool = None  # 强制下次get_redis重新创建连接
        redis = await get_redis()
        if redis:
            await send_telegram_system_alert("✅ Redis已重新连接")
    

P2 — 中期规划(本月内)

  1. 实现数据库自动备份

    # deploy/backup.sh
    #!/bin/bash
    BACKUP_DIR="/var/backups/nexus/mysql"
    mkdir -p "$BACKUP_DIR"
    mysqldump --single-transaction --routines --events Nexus | gzip > "$BACKUP_DIR/nexus_$(date +%Y%m%d).sql.gz"
    find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete  # 保留30天
    

    配置cron0 3 * * * /www/wwwroot/api.synaglobal.vip/deploy/backup.sh

  2. 接入运维监控

    • 安装 node_exporter + Prometheus + Grafana
    • 导入Nexus /health 端点到Prometheus
    • 设置关键告警规则:CPU>90%、磁盘>85%、Python进程Down、MySQL连接数>150
  3. Redis Sentinel/Cluster高可用

    • 当前单点Redis:一旦宕机,所有实时心跳数据和告警状态丢失
    • 建议部署Redis Sentinel实现自动故障切换,或至少配置Redis AOF持久化

P3 — 长期规划

  1. 容器化部署Docker Compose/K8s

    • 将FastAPI/Nginx/Redis/PHP容器化,消除环境不一致问题
    • 便于水平扩展
  2. 灰度发布策略

    • 实现蓝绿部署或canary发布机制,减少变更风险

7. 总结

Nexus的部署架构在整体设计上是稳健的,三层守护机制覆盖了进程崩溃、服务僵死、依赖服务故障等常见场景。然而,存在几个必须立即处理的风险:

  1. 单worker瓶颈 — 这是当前最致命的性能隐患,2000+服务器的Agent心跳(60秒间隔)单worker可能无法承受
  2. 循环重启风暴 — health_monitor脚本在连续失败后每分钟执行restart,可能造成服务抖动
  3. 数据库连接池超配 — 100+100的池大小已经超过MySQL 151的默认上限,多worker后问题更严重
  4. Root运行和服务用户缺失 — 安全基线问题
  5. CORS全开已修复:NEXUS_CORS_ORIGINS 环境变量白名单

短期改进优先级:

  1. 先调低数据库连接池(写死的风险 > 配置不一致的风险)
  2. 再修复health_monitor冷却期
  3. 然后评估多worker+WebSocket兼容性后启用
  4. 最后补充Nginx安全配置

以上改进建议的预计工时:P0项约2小时,P1项约4小时,P2项约2天(含Grafana部署调试)。