# 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) — 功能与数据表概览