本文记录一次真实的服务升级:把自部署的 New API 中转服务从「rc.21 + SQLite」升级到「rc.25 + 私有 PostgreSQL」,并在一个维护窗口内完成,零数据丢失。
背景与动机
New API 是一个 OpenAI-compatible 的中转网关,之前跑在 rc.21 + SQLite 上。随着渠道、模型、额度数据量增长,开始反复出现 SQLITE_BUSY、卡顿和单写者 CPU 争用。问题本质是 SQLite 的单写者模型撑不住并发写。
结论不是简单升版,而是「升级 rc.25 + 迁移到私有 PostgreSQL」两件事一起做。
迁移过程(一个维护窗口内完成)
- 停服冻结:停掉
new-api容器,冻结 SQLite,做在线备份并记录 SHA(sha256); - 初始化 schema:让
rc.25连上私有 PostgreSQL,自动建立 34 张表; - 数据导入:用 pgloader 做 data-only 导入——
create no tables + truncate + reset sequences,并把channels.channel_info列显式 CAST 成 text;最终errors=0,31/31 张表逐表行数一致; - 切配置:只改新容器的
SQL_DSN指向私有 PG,用固定的rc.25digest 启动; - 验证:
/api/status200、未鉴权/v1/models401、活跃 token 鉴权 200(32 个模型)、公网入口 200、生产日志无 DB 报错。
两个关键红线的经验
- 镜像与数据库必须联动回滚:只回退镜像、不恢复匹配的数据库,会造成二次故障。升级前我同时保留了 rc.21 + SQLite 的回滚路径。
- 软删除 token 的行为变化:rc.25 下
deleted_at非空的 token 鉴权会返回 401(rc.21 时代校验宽松)。若还有旧软删 token 要继续用,需在面板重建。
一个更隐蔽的坑
迁移后同一目录下存在两份 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 中有更完整的记录。