23 KiB
知习数据库与服务器部署方案(最终版)
定版日期:2026-05-18 | 状态:已拍板,按此执行
一、存储架构总览
知识库不需要 MongoDB。最终存储分成四类:
MySQL :权威业务数据(用户、知识库、学习记录、额度、审计)
Qdrant :向量索引(chunk embedding、语义检索)
COS :对象存储(原始文件、解析结果、备份快照)
Redis :队列 / 缓存 / 限流 / 锁
不引入的组件:
MongoDB → 不需要(没有文档型存储场景)
Elasticsearch → 第一阶段不需要(Qdrant + rerank 够用)
ClickHouse → 第一阶段不需要(OLAP 后续再说)
二、MySQL:唯一权威业务数据库
存放内容
# 用户与认证
users
auth_accounts
refresh_tokens
memberships
membership_plans
# 知识库核心
files
knowledge_bases
knowledge_sources
document_imports
knowledge_chunks
import_candidates
knowledge_items
# 学习引擎
active_recall_answers
ai_analysis_results
focus_items
review_cards
learning_activities
chat_sessions
chat_messages
# 运营与审计
ai_usage_logs
quota_usage
admin_audit_logs
backup_jobs
feedback
notifications
ID 类型(重要)
当前 Prisma schema 主键是 BigInt @default(autoincrement()),JavaScript/JSON 对 64 位整数有精度问题。
现在数据库空,必须立即改:
id String @id @default(cuid())
推荐 cuid/cuid2:适合业务 ID,前端、后端、日志、JWT、API 都好处理。以后数据多了再改会很痛苦。
生产配置
文件:/etc/mysql/conf.d/zhixi.cnf
[mysqld]
# InnoDB
innodb_buffer_pool_size = 8G
innodb_buffer_pool_instances = 4
innodb_log_file_size = 1G
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
# Connections
max_connections = 100
wait_timeout = 300
interactive_timeout = 300
# Charset
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# Slow query
slow_query_log = 1
long_query_time = 1
log_queries_not_using_indexes = 0
# Binlog(无主从复制时可关)
skip-log-bin
32G 内存分配
MySQL buffer pool 8G
Qdrant 8G–12G(动态)
Redis 1G 内
RAG Worker / 解析 4G–8G
系统 + Docker + 缓存 4G+
预留安全空间 4G+
后续调整规则:
MySQL 慢查询多 + 内存充足 → buffer pool 调到 10G–12G
Qdrant / Worker 内存吃紧 → 不再加 MySQL 内存
Too many connections → max_connections 调到 150
---
## 三、Qdrant:向量数据库
### 存放内容
```text
Collection:zhixi_chunks
├─ chunk embedding 向量(1024d,Cosine)
├─ userId / knowledgeBaseId / sourceId / chunkId(payload 索引)
├─ pageNumber / sectionTitle(元数据)
└─ deleted(bool,软删除标记)
负责的能力
语义检索(ANN Top-50 → rerank Top-5~8)
知识库问答召回
相似知识点查找
学习内容推荐
不负责
用户体系
会员额度
知识点管理
学习记录
订单支付
Qdrant 是 MySQL 的补充,不是替代。
安全策略(已拍板)
第一阶段:不公网暴露 Qdrant
优先方案:不映射端口,只在 Docker internal network 用容器名访问
调试方案:仅绑定 127.0.0.1:6333
暂不启用 API Key,但预留 QDRANT_API_KEY 环境变量
未来跨服务器访问时 → 必须启用 API Key
Docker Compose 推荐写法(不映射端口)
services:
qdrant:
image: qdrant/qdrant:latest
restart: unless-stopped
volumes:
- /data/qdrant:/qdrant/storage
networks:
- zhixi_internal
# 不写 ports,公网访问不到
backend:
image: zhixi-backend:latest
restart: unless-stopped
environment:
QDRANT_URL: http://qdrant:6333
networks:
- zhixi_internal
- zhixi_public
networks:
zhixi_internal:
internal: true # 不对外暴露
zhixi_public:
如需宿主机调试(仅绑定 localhost)
services:
qdrant:
ports:
- "127.0.0.1:6333:6333"
- "127.0.0.1:6334:6334"
不要这样写
ports:
- "6333:6333" # 暴露公网!没有 API Key 时非常危险
四、COS:对象存储
存放内容
zhixi-prod/
├─ users/{userId}/knowledge-bases/... ← 原始文件 + 解析结果
├─ users/{userId}/profile/avatar/... ← 头像
├─ users/{userId}/feedback/... ← 反馈截图
├─ system/knowledge-bases/... ← 系统内置知识库
├─ system/backups/qdrant/{date}/... ← Qdrant 快照
├─ system/backups/mysql/{date}/... ← MySQL 备份
├─ exports/users/{userId}/... ← 用户导出
└─ public/app-assets/... ← 公共资源
原则
数据库是主关系,COS 是文件仓库
权限、归属、状态永远以数据库为准
处理文件时从 COS 临时拉取,处理完删除本地临时文件
五、Redis:队列与缓存
负责
BullMQ 任务队列(文档导入、AI 分析、通知发送)
API 限流
分布式锁(防止重复导入、重复扣额度)
用户 session(备选,也可用 MySQL)
临时状态缓存
不负责
长期业务数据
向量索引
文件存储
六、服务器分工(已拍板)
总原则
现在数据库基本空,不要再把新表建到旧服务器上。唯一权威 MySQL 放 8核32G。
8核32G CVM:正式生产主服务器
部署清单:
/opt/zhixi/backend ← NestJS 主后端
/opt/zhixi/rag-worker ← Python RAG Worker
/opt/zhixi/deploy ← docker-compose.yml + 脚本
/data/docker ← Docker data-root
/data/mysql ← MySQL 数据文件
/data/redis ← Redis 数据文件
/data/qdrant ← Qdrant 存储
/data/tmp/imports ← 临时下载/解析工作区
/data/logs ← 统一日志
/data/worker-cache ← llama-index 缓存
/data/backups/mysql ← MySQL 每日备份
/data/backups/qdrant ← Qdrant 每日快照
运行服务:
Nginx(可选)
NestJS API(Node)
MySQL 8.0
Redis 7
Qdrant(Docker)
RAG Worker(Python)
AI Gateway Worker(Node)
Backup Worker(Cron)
Cron Jobs(定时清理、stale job recovery)
负责的业务:
全部用户数据、认证、会员
全部知识库数据(表 + 向量)
全部学习引擎(主动回忆、AI 诊断、复习)
全部 AI 调用与成本记录
全部后台管理与审计
4核4G 轻量云:工具服务器 / 辅助服务器
定位: 继续当工具服务器,不承载生产核心数据。
已运行服务(保留):
Web 产品页 / landing page
Gitea
适合新增的服务:
n8n ← 营销自动化、流程编排、Webhook
轻量 agent runner ← CI/CD 辅助、定时调研、通知
Uptime Kuma ← 服务监控
跳板机 ← SSH 入口
测试 / staging 环境 ← 预发布验证
Gitea Webhook 自动化 ← CI/CD 触发
营销自动化脚本 ← 定时任务
轻量后台工具 ← 不操作生产库的管理工具
不建议放 4核4G 的服务:
正式 MySQL / Redis / Qdrant ← 生产核心数据
RAG Worker / 文档解析 ← 重型 CPU/内存任务
Dify 生产环境 ← 最低 4G 但跑不稳(后面细说)
本地大模型 / 多模态模型 ← GPU/内存不够
重型爬虫 / 大量自动化任务 ← 吃满 CPU
七、4核4G 上各服务决策
1. n8n:可以放
n8n 适合放 4核4G,用来做:
营销自动化
内容生产流程编排
Gitea Webhook 触发
定时任务
数据同步
通知提醒
AI API 调用编排
运营脚本
部署方式:
Docker Compose
nginx/caddy 反代 → https://n8n.yourdomain.com
安全要求:
强密码
HTTPS
禁止公开注册
后台路径不裸奔
定期备份 n8n 数据目录
核心规则:n8n 不直接操作生产数据库。
正确方式:
n8n / agent
→ 调用 8核32G 的受控内部 API
→ 8核32G 做权限、额度、日志、落库
不要让 n8n 或 agent 变成"野生后台"。
2. Dify:第一阶段不部署
Dify 最低要求 CPU ≥ 2 Core、RAM ≥ 4 GiB(官方推荐 8 GiB 更稳)。4核4G 已有 Web 产品页 + Gitea + n8n + agent,再放 Dify 容易"能启动但卡、能用但不稳、一跑 workflow 就吃满"。
而且 Dify 和你自己的 AI Gateway / RAG Worker 有功能重叠,知习核心知识库才是优先事项。
决策:
第一阶段不部署 Dify。
后续如需实验,放 8核32G sandbox profile(不连生产库)。
# 以后如需实验:
docker compose --profile dify up -d # 用完关掉
3. 轻量 agent:可以放
适合放 4核4G 的 agent 类型:
营销内容生成 agent
定时调研 agent
Gitea issue 分析 agent
自动发布提醒 agent
数据采集辅助 agent
n8n workflow agent
小型 webhook agent
规则和 n8n 一样:agent 可以调用知习 API,但不可直接连生产 MySQL、操作 Qdrant、拿 COS 主密钥。
八、最终部署架构图
iOS / Web
↓
┌───────────────┴───────────────┐
│ │
┌───────┴──────────┐ ┌───────┴──────────┐
│ 8核32G CVM │ │ 4核4G 轻量云 │
│ (生产核心服务器) │ │ (工具/辅助服务器) │
│ │ │ │
│ ┌──────────────┐ │ │ ┌───────────────┐ │
│ │ gitea-runner │ │ CI/CD │ │ gitea-runner │ │
│ │ -prod │ │ │ │ -web │ │
│ └──────────────┘ │ │ └───────────────┘ │
│ ┌──────────────┐ │ │ ┌───────────────┐ │
│ │ NestJS API │ │ │ │ Web 产品页 │ │
│ └──────┬───────┘ │ │ │ (landing) │ │
│ │ │ │ └───────────────┘ │
│ ┌──────┴───────┐ │ │ ┌───────────────┐ │
│ │ MySQL │ │ 权威业务库 │ │ Gitea │ │
│ └──────────────┘ │ │ │ (主服务) │ │
│ ┌──────────────┐ │ │ └───────────────┘ │
│ │ Redis │ │ 队列/缓存 │ ┌───────────────┐ │
│ └──────────────┘ │ │ │ n8n │ │
│ ┌──────────────┐ │ │ └───────────────┘ │
│ │ Qdrant │ │ 向量索引 │ ┌───────────────┐ │
│ └──────────────┘ │ │ │ agent runner │ │
│ ┌──────────────┐ │ │ └───────────────┘ │
│ │ RAG Worker │ │ 解析/切片 │ ┌───────────────┐ │
│ └──────────────┘ │ │ │ Uptime Kuma │ │
│ ┌──────────────┐ │ │ └───────────────┘ │
│ │ AI Gateway │ │ AI 调度 │ │
│ └──────────────┘ │ │ (不承载正式 │
│ ┌──────────────┐ │ │ 业务数据) │
│ │ Backup+Cron │ │ 备份/清理 └───────────────────┘
│ └──────────────┘ │
│ │
│ /data (70G) │
└────────┬─────────┘
│
┌───────┴───────┐
│ 腾讯云 COS │
│ │
│ 原始文件 │
│ parsed.md │
│ OCR/Vision │
│ 备份快照 │
│ 用户头像 │
│ 导出文件 │
└───────────────┘
九、CI/CD 部署流水线
1. 总原则
Gitea 本体只放 4核4G,Runner 两台都装
服务跑在哪台服务器,Runner 就装在哪台服务器
每台 Runner 本地构建、本地部署,不跨服务器传输构建产物
不要搞成"4核 Runner 构建后端 → 传到 8核部署",多一层 SSH + 传输 + 1Mbps 带宽瓶颈。
2. Runner 分工
4核4G:gitea-runner-web
标签:web, tools, staging, docker
负责:
Web 产品页部署
Gitea Webhook 自动化
n8n / 工具服务部署
轻量 agent 更新
8核32G:gitea-runner-prod
标签:prod, backend, rag, docker
负责:
NestJS 后端部署
Prisma migration
MySQL / Redis / Qdrant docker compose 更新
RAG Worker 部署
AI Gateway 部署
备份脚本部署
3. Runner 安装
两台服务器都创建 deploy 用户(不要用 root 跑 runner):
sudo useradd -m -s /bin/bash deploy
sudo usermod -aG docker deploy
8核上注册 runner 到 4核 Gitea:
# 在 8核32G 上执行
./gitea-actions-runner register \
--name zhixi-prod-runner \
--labels prod,backend,rag,docker \
--instance https://gitea.yourdomain.com \
--token <从 Gitea Admin 获取>
4. Workflow 示例
后端部署(跑在 8核 runner):
# .gitea/workflows/deploy-backend.yml
name: deploy-backend
on:
push:
branches: [main]
paths:
- "backend/**"
- "rag-worker/**"
- "deploy/**"
jobs:
deploy:
runs-on: [prod, backend, docker]
steps:
- uses: actions/checkout@v4
- name: Build & Deploy
run: |
cd backend
pnpm install --frozen-lockfile
pnpm build
npx prisma migrate deploy
docker compose -f ../deploy/docker-compose.prod.yml up -d --build
Web 部署(跑在 4核 runner):
# .gitea/workflows/deploy-web.yml
name: deploy-web
on:
push:
branches: [main]
paths:
- "web/**"
jobs:
deploy:
runs-on: [web, docker]
steps:
- uses: actions/checkout@v4
- name: Build & Deploy
run: |
cd web
pnpm install --frozen-lockfile
pnpm build
docker compose -f docker-compose.web.yml up -d --build
5. 密钥管理
生产密钥不写入仓库,放在 8核服务器本地或 Gitea Secrets:
/opt/zhixi/env/.env.production
必需密钥:
DATABASE_URL
REDIS_URL
QDRANT_URL
COS_SECRET_ID / COS_SECRET_KEY
DEEPSEEK_API_KEY
SILICONFLOW_API_KEY
BAIDU_OCR_KEY
JWT_SECRET
RAG_WORKER_SECRET(内部 API 认证)
6. Gitea 挂了不影响生产
Gitea 只影响代码仓库和部署流水线
8核上的后端、MySQL、Redis、Qdrant 继续运行
最多暂时不能自动部署新版本
十、迁移执行计划
因为现在数据库基本空,迁移很简单,按此顺序推进:
第一步:8核32G 基础环境
1. 挂载 /data 数据盘
2. 安装 Docker / Docker Compose
3. 配置 Docker data-root → /data/docker
4. 创建所有 /data 子目录
5. 创建 deploy 用户(用于 Runner 和部署)
第二步:部署核心服务
6. 部署 MySQL → /data/mysql,创建数据库 zhixi_prod
7. 部署 Redis → /data/redis
8. 部署 Qdrant → /data/qdrant,创建 collection zhixi_chunks
9. 配置数据库连接:DATABASE_URL / REDIS_URL / QDRANT_URL
第三步:数据库迁移
9. 修改 Prisma schema:BigInt → String(cuid)
10. 初始化空库 migration
11. 4核4G mysqldump → 导入 8核32G(仅登录相关 2~3 张表)
12. 配置备份脚本(MySQL + Qdrant + 同步 COS)
第四步:CI/CD 搭建
14. 8核32G 安装 gitea-runner-prod(标签 prod, backend, rag, docker)
15. 4核4G 安装 gitea-runner-web(标签 web, tools, docker)
16. 配置 Gitea Secrets(密钥不入仓库)
17. 编写 deploy-backend.yml / deploy-web.yml
18. 测试 push → 自动构建 → 自动部署流水线
第五步:DNS 与后端切换
域名规划:
zhixi.app / api.zhixi.app → 8核32G(NestJS 后端 API)
www.zhixi.app / zhixi.app → 4核4G(Web 产品页)
n8n.zhixi.app → 4核4G(n8n)
gitea.zhixi.app → 4核4G(Gitea)
19. 确认 8核32G 上 NestJS 正常运行(先用 IP:3000 测试)
20. DNS 主域名(api.zhixi.app / 主站)从 4核4G 切换到 8核32G
21. Caddy/Nginx 配置 SSL 证书(Let's Encrypt 自动申请)
22. 修改 DATABASE_URL 指向新 MySQL
23. 测试 iOS 登录功能(通过域名 + HTTPS)
24. 4核4G 旧后端保留 7~14 天作为回滚备用
25. n8n / Gitea 的子域名保持指向 4核4G(不动)
当前状态:DNS 尚在 4核4G。切换完成后告知,更新本文档状态。
第六步:知识库开发
23. 在 8核32G 上按知识库设计文档建表
24. 实现文件上传 → COS
25. 部署 RAG Worker
26. 打通索引流程 → 学习流程
十一、最终拍板清单
# 存储架构
1. 唯一权威 MySQL 放 8核32G,4核4G 不再建新表
2. ID 类型立即从 BigInt 改为 String(cuid),趁库空
3. Redis 放 8核32G(队列 / 缓存 / 限流 / 锁)
4. Qdrant 放 8核32G(向量索引)
5. COS 继续作为文件 + 备份存储
6. 不引入 MongoDB / Elasticsearch / ClickHouse
# 8核32G:生产核心服务器
7. 全量承载 NestJS + MySQL + Redis + Qdrant + RAG Worker + AI Gateway
8. 负责全部用户数据、知识库、学习引擎、成本记录、后台审计
9. 安装 gitea-runner-prod(负责后端/知识库/RAG 部署)
# 4核4G:工具服务器 / 辅助服务器
10. 保留 Gitea 主服务 + Web 产品页
11. 安装 gitea-runner-web(负责 Web/工具/n8n 部署)
12. 可以加 n8n(营销自动化、Webhook、流程编排)
13. 可以加轻量 agent runner(不直接操作生产库)
14. 可以加 Uptime Kuma 监控
15. Dify 第一阶段不部署(后续如需实验放 8核32G sandbox)
16. 不承载正式 MySQL / Qdrant / Redis / RAG Worker
# CI/CD
17. Gitea 本体只放 4核4G,Runner 两台都装
18. 服务跑在哪台服务器,Runner 就装在哪台服务器
19. 生产密钥放 Gitea Secrets 或服务器本地 .env,不写入仓库
20. Runner 使用 deploy 用户,不用 root
# 安全边界
21. n8n / agent 调用知习受控 API,不直连生产库
22. 迁移完成后 4核4G 旧后端保留 7~14 天作为回滚备用
后续不会再有一次大的数据库迁移。
十二、仍存缺陷与待决策项
以下是当前方案中尚未覆盖或需要你拍板的点,按风险等级排序。
🔴 高风险(上线前必须定)
| # | 问题 | 现状 | 建议 |
|---|---|---|---|
| 1 | 3Mbps 公网带宽 | 8核32G 3Mbps | 日常增量文件(单文件 ≤20MB)影响可控。大文件下载 COS + 备份上传走后台队列异步处理,不阻塞 API。首次部署大量依赖包安装可能稍慢,耐心等待即可。 |
| 2 | Qdrant 无内置认证 | 已定 | 第一阶段不公网暴露。优先不映射端口(Docker internal network),需调试时仅绑定 127.0.0.1:6333。暂不启用 API Key,预留 QDRANT_API_KEY 配置。跨服务器访问时必须启用。 |
| 3 | HTTPS 证书 | 已定:免费证书(Let's Encrypt) | 域名解析当前指向 4核4G,待切换到 8核32G。切换后:域名 → 8核32G 公网 IP → Caddy/Nginx 反代 → 本地 NestJS:3000。Caddy 自动申请续期。 |
| 4 | MySQL 配置调优 | 已定 | innodb_buffer_pool_size=8G,max_connections=100,完整配置见下方 MySQL 配置小节。后续观察慢查询/内存压力再调。 |
🟡 中风险(迁移前应定)
| # | 问题 | 现状 | 建议 |
|---|---|---|---|
| 5 | Redis 持久化 | 未配置 | 推荐 AOF everysec + RDB 双开。Redis 主要做队列(BullMQ),任务丢失影响可控但要尽量保留。 |
| 6 | Docker 容器网络规划 | 未定义 | 建议一个 zhixi 自定义 bridge 网络,MySQL/Redis/Qdrant 只监听 localhost 或容器内网,不绑定 0.0.0.0。 |
| 7 | 日志轮转与保留 | /data/logs 目录已规划但无策略 | 建议 logrotate:每天轮转,保留 30 天,压缩。Worker 日志量可能较大,需要单独评估。 |
| 8 | 健康检查端点 | 未定义 | NestJS 需 /health 端点(返回 DB/Redis/Qdrant 连通性)。Uptime Kuma 可用此端点监控。 |
| 9 | 两服务器间通信 | 内网还是公网? | 看腾讯云是否支持同地域内网互通(北京)。如果可以,Gitea → Runner 通信走内网更快。如果不能,Runner 通过公网拉取 Gitea 任务。 |
| 10 | COS 带宽成本 | 备份上传/下载走公网 | COS 同地域内网访问免费。确认 8核32G 和 COS 都在"北京"地域,使用内网 Endpoint(cos.ap-beijing.myqcloud.com 的内网域名)。 |
🟢 低风险(后续迭代时再定)
| # | 问题 | 现状 | 建议 |
|---|---|---|---|
| 11 | API 版本管理 | 未定义 | 建议 /api/v1/... 前缀,为后续 Breaking Change 留空间。 |
| 12 | 灰度/蓝绿部署 | 未涉及 | 第一阶段不需要。先单实例跑稳,后续再考虑 docker compose 滚动更新。 |
| 13 | 数据库读写分离 | 未涉及 | 第一阶段不需要。MySQL 单实例完全够。 |
| 14 | 异地备份 | COS 在北京 | COS 本身支持跨地域复制。如果预算允许,可以复制到另一个地域的 bucket。目前本地 + COS 同地域已较安全。 |
| 15 | 4核4G 最终去留 | 迁移后保留 7~14 天 | 后续如果 4核4G 作为长期工具服务器,建议保留。如果成本敏感且 8核32G 完全够用,可以到期前评估是否下线。 |
| 16 | Docker Compose 文件结构 | 未定义 | 建议 deploy/docker-compose.prod.yml 统一管理 8核32G 上的所有服务,用一个 compose 文件管理容器间的启动顺序和网络。 |
十三、文档关联索引
本文档应与其他设计文档配合使用:
知识库设计.MD → 数据模型、API 设计、RAG 流程、额度系统
服务器与数据库部署方案.MD → 本文档:服务器分工、存储架构、CI/CD
(后续)Prisma Schema → 具体表结构实现
(后续)docker-compose.yml → 容器编排配置