Blog

本文记录一次真实的服务升级:把自部署的 New API 中转服务从「rc.21 + SQLite」升级到「rc.25 + 私有 PostgreSQL」,并在一个维护窗口内完成,零数据丢失。

背景与动机

New API 是一个 OpenAI-compatible 的中转网关,之前跑在 rc.21 + SQLite 上。随着渠道、模型、额度数据量增长,开始反复出现 SQLITE_BUSY、卡顿和单写者 CPU 争用。问题本质是 SQLite 的单写者模型撑不住并发写。

结论不是简单升版,而是「升级 rc.25 + 迁移到私有 PostgreSQL」两件事一起做。

迁移过程(一个维护窗口内完成)

  1. 停服冻结:停掉 new-api 容器,冻结 SQLite,做在线备份并记录 SHA(sha256);
  2. 初始化 schema:让 rc.25 连上私有 PostgreSQL,自动建立 34 张表;
  3. 数据导入:用 pgloader 做 data-only 导入——create no tables + truncate + reset sequences,并把 channels.channel_info 列显式 CAST 成 text;最终 errors=0,31/31 张表逐表行数一致;
  4. 切配置:只改新容器的 SQL_DSN 指向私有 PG,用固定的 rc.25 digest 启动;
  5. 验证/api/status 200、未鉴权 /v1/models 401、活跃 token 鉴权 200(32 个模型)、公网入口 200、生产日志无 DB 报错。

两个关键红线的经验

一个更隐蔽的坑

迁移后同一目录下存在两份 compose:生产用的 docker-compose.prod-pg.yml(带 SQL_DSN)和旧的 docker-compose.yml(SQLite)。如果重启时不带 -f 指定生产 compose,容器会静默回退到 SQLite,导致渠道列表旧、额度对不上、日志刷 SQLITE_BUSY

判定当前用哪个库:docker logs new-api 看启动日志——using PostgreSQL as database 是正常,SQL_DSN not set, using SQLite as database 就是踩坑了。

小结

这次迁移的体会是:比「能跑」更重要的是「能判定当前状态、能安全回滚」。上面这条明暗线,都值得在迁移前写进检查清单。

相关经验在个人知识库 50-wiki/服务器服务盘点.md 中有更完整的记录。