Files
dekun 52aca456e9 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>
2026-07-01 08:11:42 +08:00

272 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. 安装 PostgreSQLUbuntu
```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) — 功能与数据表概览