Add PostgreSQL production backend to eliminate SQLite lock contention.
Support DATABASE_URL with connection pooling, pg_dump backups, SQLite migration script, and deploy_postgres.sh with docs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+44
-18
@@ -1,6 +1,15 @@
|
||||
# 数据备份与恢复
|
||||
|
||||
qihuo 支持自动备份 SQLite 数据库与复盘附件,生成可在其他 Linux 服务器恢复的压缩包。
|
||||
qihuo 支持自动备份数据库与复盘附件,生成可在其他 Linux 服务器恢复的压缩包。
|
||||
|
||||
存储后端由 `.env` 决定:
|
||||
|
||||
| 后端 | 备份包内主文件 | 说明 |
|
||||
|------|----------------|------|
|
||||
| SQLite(默认) | `futures.db` | 本地单文件库 |
|
||||
| PostgreSQL | `postgres_dump.sql` | `pg_dump` 逻辑备份 |
|
||||
|
||||
PostgreSQL 部署与迁移见 **[POSTGRES.md](./POSTGRES.md)**。
|
||||
|
||||
---
|
||||
|
||||
@@ -8,13 +17,14 @@ qihuo 支持自动备份 SQLite 数据库与复盘附件,生成可在其他 Li
|
||||
|
||||
| 内容 | 说明 |
|
||||
|------|------|
|
||||
| `futures.db` | 主库:账号、交易记录、设置、统计缓存等 |
|
||||
| `futures.db` | SQLite 主库(仅 SQLite 模式) |
|
||||
| `postgres_dump.sql` | PostgreSQL 逻辑备份(仅 PostgreSQL 模式) |
|
||||
| `uploads/` | 复盘截图、自动 K 线图(若存在) |
|
||||
| `manifest.json` | 备份时间与文件清单 |
|
||||
| `manifest.json` | 备份时间、**backend** 字段、文件清单 |
|
||||
| `RESTORE.md` | 包内恢复说明 |
|
||||
| `restore.sh` | 一键恢复脚本 |
|
||||
|
||||
**不包含** `.env`(含 CTP 密码等敏感信息),请单独安全保管或在新服务器重新配置。
|
||||
**不包含** `.env`(含 CTP 密码、`DATABASE_URL` 等),请单独安全保管或在新服务器重新配置。
|
||||
|
||||
---
|
||||
|
||||
@@ -40,6 +50,8 @@ QIHUO_BACKUP_DIR=/data/qihuo_backup
|
||||
- **保留份数**:默认保留最近 **30** 份,超出自动删除最旧文件
|
||||
- **下载**:列表中点击「下载」获取压缩包
|
||||
|
||||
PostgreSQL 模式下需服务器已安装 `pg_dump`(`apt install postgresql-client` 或完整 `postgresql` 包)。
|
||||
|
||||
---
|
||||
|
||||
## 在新服务器恢复
|
||||
@@ -55,6 +67,13 @@ cd /root
|
||||
tar -xzf qihuo_backup_20260626_030015.tar.gz
|
||||
cd qihuo_backup_20260626_030015
|
||||
chmod +x restore.sh
|
||||
|
||||
# SQLite:直接恢复 futures.db
|
||||
RESTORE_DIR=/opt/qihuo ./restore.sh
|
||||
|
||||
# PostgreSQL:先配置 /opt/qihuo/.env 的 DATABASE_URL,再执行
|
||||
export RESTORE_DIR=/opt/qihuo
|
||||
# 若 .env 在 RESTORE_DIR 下且含 DATABASE_URL,restore.sh 会自动 source
|
||||
./restore.sh
|
||||
```
|
||||
|
||||
@@ -64,28 +83,32 @@ chmod +x restore.sh
|
||||
RESTORE_DIR=/opt/qihuo ./restore.sh
|
||||
```
|
||||
|
||||
也可通过环境变量固定默认恢复目录:
|
||||
|
||||
```bash
|
||||
QIHUO_RESTORE_DIR=/opt/qihuo
|
||||
```
|
||||
|
||||
### 方式二:手工复制
|
||||
### 方式二:手工复制(SQLite)
|
||||
|
||||
```bash
|
||||
tar -xzf qihuo_backup_20260626_030015.tar.gz
|
||||
cd qihuo_backup_20260626_030015
|
||||
pm2 stop qihuo # 或停止当前进程
|
||||
pm2 stop qihuo
|
||||
cp futures.db /opt/qihuo/futures.db
|
||||
cp -a uploads/. /opt/qihuo/uploads/ # 若有 uploads
|
||||
cp -a uploads/. /opt/qihuo/uploads/
|
||||
pm2 restart qihuo
|
||||
```
|
||||
|
||||
### 方式三:手工导入(PostgreSQL)
|
||||
|
||||
```bash
|
||||
pm2 stop qihuo
|
||||
export DATABASE_URL=postgresql://qihuo:密码@127.0.0.1:5432/qihuo
|
||||
psql "$DATABASE_URL" -f postgres_dump.sql
|
||||
cp -a uploads/. /opt/qihuo/uploads/
|
||||
pm2 restart qihuo
|
||||
```
|
||||
|
||||
### 恢复后检查清单
|
||||
|
||||
1. 已部署 qihuo 代码与 Python 虚拟环境(见 [DEPLOY.md](./DEPLOY.md))
|
||||
2. 已配置 `.env`(`SECRET_KEY`、CTP 账号等)
|
||||
3. 数据库文件权限正确(运行用户可读写的 `futures.db`)
|
||||
2. 已配置 `.env`(`DATABASE_URL` 或 SQLite、`SECRET_KEY`、CTP 账号等)
|
||||
3. PostgreSQL:库已创建且 `DATABASE_URL` 可连接
|
||||
4. 访问 Web 登录,检查交易记录、统计页是否正常
|
||||
5. CTP 模式需在新环境重新连接柜台
|
||||
|
||||
@@ -94,8 +117,9 @@ pm2 restart qihuo
|
||||
## 注意事项
|
||||
|
||||
- **恢复前务必停止 qihuo**,避免进程占用数据库导致覆盖不完整
|
||||
- 备份使用 SQLite `backup` API,并在 WAL 模式下尝试 checkpoint,降低锁冲突风险
|
||||
- 自动备份在应用后台线程执行,与 Web 服务同进程;PM2 重启不影响已生成的历史压缩包
|
||||
- SQLite 备份使用 SQLite `backup` API,并在 WAL 模式下尝试 checkpoint
|
||||
- PostgreSQL 备份使用 `pg_dump`,恢复使用 `psql -f`
|
||||
- 自动备份在应用后台线程执行,与 Web 服务同进程
|
||||
- 大体积 `uploads/` 会使压缩包变大,可按需定期清理无用截图
|
||||
- 不要将含 `.env`、数据库的压缩包上传到公开网盘
|
||||
|
||||
@@ -107,13 +131,15 @@ pm2 restart qihuo
|
||||
|------|------|
|
||||
| 设置页无备份列表 | 检查 `/root/qihuo_backup` 目录权限,进程需可写 |
|
||||
| 立即备份无反应 | 查看 PM2 日志;可能上一任务仍在进行 |
|
||||
| PostgreSQL 备份失败 | 安装 `postgresql-client`;检查 `DATABASE_URL` |
|
||||
| 下载 404 | 文件名须为系统生成的 `qihuo_backup_*.tar.gz` |
|
||||
| 恢复后无法登录 | 确认 `futures.db` 已覆盖到实际运行目录 |
|
||||
| 恢复后无法登录 | 确认数据已导入实际使用的库(SQLite 文件或 PG) |
|
||||
| 恢复后 CTP 连不上 | 在新服务器配置正确的 `.env` CTP 参数 |
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [POSTGRES.md](./POSTGRES.md) — PostgreSQL 一键部署、迁移、备份恢复
|
||||
- [DEPLOY.md](./DEPLOY.md) — 部署与目录结构
|
||||
- [FEATURES.md](./FEATURES.md) — 功能与路由一览
|
||||
|
||||
+17
-2
@@ -12,7 +12,7 @@
|
||||
| 运行用户 | `root`(与 `deploy.sh` / PM2 配置一致) |
|
||||
| 服务端口 | `6600` |
|
||||
| 进程管理 | PM2,应用名 `qihuo` |
|
||||
| 数据库 | SQLite `futures.db` |
|
||||
| 数据库 | **生产推荐 PostgreSQL**(见 [POSTGRES.md](./POSTGRES.md));未配置 `DATABASE_URL` 时使用 SQLite `futures.db` |
|
||||
| 仓库 | https://git.bz121.com/dekun/qihuo.git |
|
||||
|
||||
---
|
||||
@@ -58,6 +58,21 @@ bash deploy.sh
|
||||
|
||||
部署完成后访问:`http://<服务器IP>:6600`
|
||||
|
||||
### PostgreSQL 生产库(推荐)
|
||||
|
||||
消除 SQLite 并发 `database is locked`,一键安装 PostgreSQL 并迁移:
|
||||
|
||||
```bash
|
||||
cd /opt/qihuo
|
||||
git pull
|
||||
# 新装 PostgreSQL + 空库
|
||||
sudo bash scripts/deploy_postgres.sh
|
||||
# 从现有 futures.db 迁移
|
||||
MIGRATE_SQLITE=1 sudo bash scripts/deploy_postgres.sh
|
||||
```
|
||||
|
||||
完整说明、手动步骤、备份恢复见 **[POSTGRES.md](./POSTGRES.md)**。
|
||||
|
||||
> 再次部署只需 `cd /opt/qihuo && bash deploy.sh`,无需手工装 locale 或改前置地址。
|
||||
|
||||
---
|
||||
@@ -334,7 +349,7 @@ ufw allow 6600/tcp
|
||||
| **CTP 连接超时** | SimNow 地址/账号/非交易时段 | 核对 `.env` 与 SimNow 官网前置 |
|
||||
| **下单监控无持仓** | 未连接 CTP 或确实无仓 | 先点「连接 CTP」 |
|
||||
| **`Could not resolve host`** | 服务器 DNS 故障 | 配置 systemd-resolved 公共 DNS,见下方 |
|
||||
| `database is locked` | SQLite 并发 | 更新代码后重启 |
|
||||
| `database is locked` | SQLite 并发 | **推荐改 PostgreSQL**:`MIGRATE_SQLITE=1 bash scripts/deploy_postgres.sh`,见 [POSTGRES.md](./POSTGRES.md) |
|
||||
| `git pull` 冲突 | 本地有修改 / SCP 部署 | `git fetch && git reset --hard origin/main` |
|
||||
|
||||
查看应用是否在监听:
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
| [SIMNOW.md](./SIMNOW.md) | SimNow 仿真注册与接入 |
|
||||
| [CTP_LIVE.md](./CTP_LIVE.md) | **期货公司实盘 CTP** 与开平仓对比 |
|
||||
| [DEPLOY.md](./DEPLOY.md) | 部署说明 |
|
||||
| [POSTGRES.md](./POSTGRES.md) | **PostgreSQL 生产库**(一键部署、迁移、备份恢复) |
|
||||
| [BACKUP.md](./BACKUP.md) | 数据备份与恢复 |
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
# PostgreSQL 生产数据库
|
||||
|
||||
qihuo 支持两种存储后端:
|
||||
|
||||
| 模式 | 配置 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| **SQLite**(默认) | 不设置 `DATABASE_URL` | 本地开发、单机轻量试用 |
|
||||
| **PostgreSQL**(推荐生产) | `.env` 中 `DATABASE_URL=postgresql://...` | 7×24 运行、多线程并发、消除 `database is locked` |
|
||||
|
||||
配置 `DATABASE_URL` 后,应用自动使用 **连接池**(默认 2–20 连接),无需改业务代码。
|
||||
|
||||
---
|
||||
|
||||
## 为什么用 PostgreSQL
|
||||
|
||||
SQLite 在同一文件上同一时刻只允许一个写者。qihuo 单进程内有多路后台线程(持仓刷新、止盈守护、挂单同步、统计缓存等)和 HTTP 请求同时写库,容易出现:
|
||||
|
||||
```
|
||||
position worker failed: database is locked
|
||||
bootstrap position snapshot: database is locked
|
||||
```
|
||||
|
||||
PostgreSQL 面向并发读写设计,多连接、行级锁、连接池,与专业交易软件「服务端数据库 + 内存快照」的思路一致。
|
||||
|
||||
---
|
||||
|
||||
## 一键部署(新服务器 / 已有 qihuo)
|
||||
|
||||
在已执行过 `deploy.sh` 的服务器上,以 **root** 运行:
|
||||
|
||||
```bash
|
||||
cd /opt/qihuo
|
||||
git pull # 获取最新代码
|
||||
sudo bash scripts/deploy_postgres.sh
|
||||
```
|
||||
|
||||
脚本会自动:
|
||||
|
||||
1. 安装 `postgresql` / `postgresql-contrib`
|
||||
2. 创建数据库 `qihuo`、用户 `qihuo`(随机密码,终端会打印)
|
||||
3. 写入 `/opt/qihuo/.env` 的 `DATABASE_URL`、`PG_POOL_MIN`、`PG_POOL_MAX`
|
||||
4. `pip install psycopg psycopg-pool`
|
||||
5. 执行 `init_db()` 建表
|
||||
6. `pm2 restart qihuo --update-env`
|
||||
|
||||
### 从现有 SQLite 迁移
|
||||
|
||||
若 `/opt/qihuo/futures.db` 已有数据:
|
||||
|
||||
```bash
|
||||
cd /opt/qihuo
|
||||
MIGRATE_SQLITE=1 sudo bash scripts/deploy_postgres.sh
|
||||
```
|
||||
|
||||
会:
|
||||
|
||||
- 初始化 PostgreSQL 表结构
|
||||
- 运行 `scripts/migrate_sqlite_to_postgres.py` 导入全部表
|
||||
- 将旧库备份为 `futures.db.pre_pg.YYYYMMDD_HHMMSS`(可用 `BACKUP_SQLITE=0` 跳过)
|
||||
|
||||
迁移前建议先做一次 Web 设置页 **立即备份** 或:
|
||||
|
||||
```bash
|
||||
cp /opt/qihuo/futures.db /root/futures.db.bak.$(date +%Y%m%d)
|
||||
pm2 stop qihuo
|
||||
MIGRATE_SQLITE=1 sudo bash scripts/deploy_postgres.sh
|
||||
```
|
||||
|
||||
### 环境变量(可选)
|
||||
|
||||
| 变量 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `APP_DIR` | `/opt/qihuo` | 应用目录 |
|
||||
| `PG_DB` | `qihuo` | 数据库名 |
|
||||
| `PG_USER` | `qihuo` | 数据库用户 |
|
||||
| `PG_PASSWORD` | 随机 | 不设则脚本生成 |
|
||||
| `PG_HOST` | `127.0.0.1` | 主机 |
|
||||
| `PG_PORT` | `5432` | 端口 |
|
||||
| `MIGRATE_SQLITE` | `0` | `1` 时从 `futures.db` 迁移 |
|
||||
| `BACKUP_SQLITE` | `1` | 迁移后是否备份旧 SQLite 文件 |
|
||||
|
||||
---
|
||||
|
||||
## 手动部署
|
||||
|
||||
### 1. 安装 PostgreSQL(Ubuntu)
|
||||
|
||||
```bash
|
||||
apt update
|
||||
apt install -y postgresql postgresql-contrib
|
||||
systemctl enable postgresql
|
||||
systemctl start postgresql
|
||||
```
|
||||
|
||||
### 2. 创建库与用户
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql <<'SQL'
|
||||
CREATE USER qihuo WITH PASSWORD '请改为强密码';
|
||||
CREATE DATABASE qihuo OWNER qihuo;
|
||||
GRANT ALL PRIVILEGES ON DATABASE qihuo TO qihuo;
|
||||
SQL
|
||||
```
|
||||
|
||||
### 3. 配置 `.env`
|
||||
|
||||
```bash
|
||||
cd /opt/qihuo
|
||||
cat >> .env <<'EOF'
|
||||
|
||||
DATABASE_URL=postgresql://qihuo:请改为强密码@127.0.0.1:5432/qihuo
|
||||
PG_POOL_MIN=2
|
||||
PG_POOL_MAX=20
|
||||
EOF
|
||||
```
|
||||
|
||||
### 4. 安装 Python 驱动并初始化
|
||||
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
export $(grep -v '^#' .env | xargs) # 或手动 export DATABASE_URL
|
||||
python3 -c "from app import init_db; init_db()"
|
||||
```
|
||||
|
||||
### 5. 迁移 SQLite(可选)
|
||||
|
||||
```bash
|
||||
python3 scripts/migrate_sqlite_to_postgres.py --sqlite /opt/qihuo/futures.db
|
||||
# 仅预览行数:
|
||||
python3 scripts/migrate_sqlite_to_postgres.py --dry-run
|
||||
```
|
||||
|
||||
### 6. 重启应用
|
||||
|
||||
```bash
|
||||
pm2 restart qihuo --update-env
|
||||
pm2 logs qihuo --lines 30
|
||||
```
|
||||
|
||||
启动后日志中不应再频繁出现 `database is locked`(SQLite 特有)。
|
||||
|
||||
---
|
||||
|
||||
## 连接池
|
||||
|
||||
| 变量 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `PG_POOL_MIN` | `2` | 池内最少连接 |
|
||||
| `PG_POOL_MAX` | `20` | 池内最多连接 |
|
||||
|
||||
每个 HTTP 请求 / 后台 worker 从池中借连接,用毕归还。PM2 请保持 **`instances: 1`**(见 `ecosystem.config.cjs`);若要多实例,共用同一 `DATABASE_URL` 即可,PostgreSQL 可承受。
|
||||
|
||||
---
|
||||
|
||||
## 备份
|
||||
|
||||
### 方式一:系统设置页(推荐)
|
||||
|
||||
**系统设置 → 数据备份与恢复 → 立即备份**
|
||||
|
||||
PostgreSQL 模式下包内为 `postgres_dump.sql`(`pg_dump` 逻辑备份),而非 `futures.db`。
|
||||
|
||||
### 方式二:命令行
|
||||
|
||||
```bash
|
||||
# 需与 .env 中 DATABASE_URL 一致
|
||||
source /opt/qihuo/venv/bin/activate
|
||||
set -a && source /opt/qihuo/.env && set +a
|
||||
pg_dump --no-owner --no-acl -f /root/qihuo_backup/manual_$(date +%Y%m%d_%H%M%S).sql "$DATABASE_URL"
|
||||
```
|
||||
|
||||
### 方式三:每日自动备份
|
||||
|
||||
设置页开启 **每日自动备份**(默认 03:00),保留份数默认 30。备份目录默认 `/root/qihuo_backup`。
|
||||
|
||||
详见 [BACKUP.md](./BACKUP.md)。
|
||||
|
||||
---
|
||||
|
||||
## 恢复
|
||||
|
||||
### 从 qihuo 备份包恢复(含 restore.sh)
|
||||
|
||||
```bash
|
||||
pm2 stop qihuo
|
||||
cd /root
|
||||
tar -xzf qihuo_backup_YYYYMMDD_HHMMSS.tar.gz
|
||||
cd qihuo_backup_YYYYMMDD_HHMMSS
|
||||
# 确保 /opt/qihuo/.env 已配置 DATABASE_URL
|
||||
export RESTORE_DIR=/opt/qihuo
|
||||
chmod +x restore.sh
|
||||
./restore.sh
|
||||
pm2 restart qihuo
|
||||
```
|
||||
|
||||
`manifest.json` 中 `"backend": "postgres"` 表示包内为 `postgres_dump.sql`。
|
||||
|
||||
### 手工 psql 恢复
|
||||
|
||||
```bash
|
||||
pm2 stop qihuo
|
||||
export DATABASE_URL=postgresql://qihuo:密码@127.0.0.1:5432/qihuo
|
||||
# 空库或需覆盖的库
|
||||
psql "$DATABASE_URL" -f /path/to/postgres_dump.sql
|
||||
cp -a uploads_backup/. /opt/qihuo/uploads/ # 若有附件
|
||||
pm2 restart qihuo
|
||||
```
|
||||
|
||||
### 恢复后检查
|
||||
|
||||
1. Web 登录正常
|
||||
2. **交易记录**、**统计** 页数据完整
|
||||
3. **系统设置** 中 CTP、资金等配置仍在
|
||||
4. 连接 CTP,持仓页刷新正常
|
||||
5. `pm2 logs qihuo` 无持续数据库报错
|
||||
|
||||
---
|
||||
|
||||
## 回退到 SQLite
|
||||
|
||||
1. `pm2 stop qihuo`
|
||||
2. 注释或删除 `.env` 中 `DATABASE_URL`
|
||||
3. 确保 `/opt/qihuo/futures.db` 存在(可用迁移前备份 `futures.db.pre_pg.*`)
|
||||
4. `pm2 restart qihuo`
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 现象 | 可能原因 | 处理 |
|
||||
|------|----------|------|
|
||||
| `未安装 psycopg` | 未 pip install | `pip install -r requirements.txt` |
|
||||
| `pg_dump 失败` | 未装客户端 / URL 错误 | `apt install postgresql-client`;检查 `DATABASE_URL` |
|
||||
| 迁移后缺表 | 未 init_db | `python3 -c "from app import init_db; init_db()"` 后重跑迁移 |
|
||||
| 登录失败 | 只恢复了 SQL 未恢复 settings | 检查 `settings` 表是否有 `admin_password_hash` |
|
||||
| 连接拒绝 | PostgreSQL 未启动 | `systemctl status postgresql` |
|
||||
| 仍见 locked | 未切到 PG,仍用 SQLite | `grep DATABASE_URL /opt/qihuo/.env`;`pm2 restart --update-env` |
|
||||
|
||||
### 验证当前后端
|
||||
|
||||
```bash
|
||||
cd /opt/qihuo && source venv/bin/activate
|
||||
set -a && source .env && set +a
|
||||
python3 -c "from db_conn import database_label, db_backend; print(db_backend(), database_label())"
|
||||
```
|
||||
|
||||
应输出 `postgres PostgreSQL (...)`。
|
||||
|
||||
### 查看 PostgreSQL 连接
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql -d qihuo -c "SELECT count(*) FROM pg_stat_activity WHERE datname='qihuo';"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全建议
|
||||
|
||||
- `DATABASE_URL` 含密码,勿提交到 git;`.env` 权限建议 `chmod 600`
|
||||
- 备份包、`postgres_dump.sql` 含交易与账号数据,勿上传公开网盘
|
||||
- 生产库仅监听 `127.0.0.1`,不暴露 5432 到公网
|
||||
- 定期测试 **备份 → 解压 → restore.sh → 登录** 全流程
|
||||
|
||||
---
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [DEPLOY.md](./DEPLOY.md) — 应用一键部署
|
||||
- [BACKUP.md](./BACKUP.md) — 备份策略与设置页说明
|
||||
- [FEATURES.md](./FEATURES.md) — 功能与数据表概览
|
||||
Reference in New Issue
Block a user