相关规则见 docs/architecture/23-ops.md 第 7 节和 docs/architecture/07-data.md 第 4.1 节。此处介绍具体流程。
安全升级的保证
**版本 R 可以正确使用架构 R 和 R 减 1 的数据库模式。**每项数据库模式变更都分为扩展、过渡和收缩三个阶段:
- 扩展:添加新列、表或索引。旧代码会忽略它。
- 过渡:至少持续一个版本;新代码同时写入两种结构,并读取新结构;可续跑的任务会回填旧行。
- 收缩:在后续版本中单独移除旧结构。
因此,在滚动升级的任何时刻,新旧进程都可以共用同一个数据库。系统没有向下迁移:如果迁移在一小时前删除了某列,就无法恢复这一小时内写入的数据。
每个版本的 schema-compat CI 任务都会用新版数据库模式运行上一版本的测试,以检查这一保证。
开始之前
- 阅读版本说明。需要维护窗口的版本会明确说明,并估算所需时长;每个版本最多只有一次这样的发布。
- 执行恢复演练,或确认此版本的演练已成功(见 backup-restore.md)。演练失败会阻止升级。
- 创建基础备份:
docker compose -f docker/compose.yaml --profile backup run --rm backup。
单主机上的 Docker Compose
export QUIRE_RELEASE=2026.10.0 # or set it in docker/.env
docker compose -f docker/compose.yaml pull # or build
docker compose -f docker/compose.yaml run --rm migrate
docker compose -f docker/compose.yaml up -d --no-deps web content collab
docker compose -f docker/compose.yaml up -d --no-deps worker scheduler此顺序是有意安排的:
- 先迁移,旧版本仍在处理流量时执行。扩展迁移对旧版本不可见。
- 然后升级 Web 层。收到 SIGTERM 后,每个 Web 进程会将
/readyz状态设为draining,在 30 秒内完成正在处理的请求,以重连提示关闭流,然后退出。stop_grace_period为 40 秒,因此 Compose 不会中断正常的退出过程。 - 最后升级 worker,先确保产生新事件格式,再让新消费者开始处理。Worker 会立即停止获取任务,并有 120 秒时间完成处理。无法完成的任务会在其他位置重新获取;由于每个任务都有幂等性,这是安全的。Scheduler 会在下一个周期移交领导权。
在单主机上,Compose 会依次替换各个容器,因此每项服务都会短暂中断。要完全消除中断,可在自己的代理后运行两个 Web 层容器(通过覆盖文件添加没有发布端口的第二个 web 服务),每次只重建一个,并等待其报告健康后再重建另一个。
多主机或编排器
按相同顺序操作:从单个任务运行一次迁移,以 surge 为 1、不可用实例数为 0 的方式滚动升级 Web 层,然后升级 worker。就绪探针指向 /readyz,存活探针指向 /healthz。
有专用租户数据库时,migrate 步骤会先迁移控制数据库,然后逐个迁移 ops.tenant_database 中列出的每个数据库,并为每个数据库分别加锁。某个租户数据库迁移失败不会影响其他数据库。全部迁移完成后,会比较各数据库的迁移记录;如果任何数据库应用的迁移与控制数据库不完全一致,命令会以非零状态退出并指出哪些数据库落后或超前。同一命令也会在每个数据库中安装队列表,因为 worker 会在固定租户写入任务的数据库中读取任务。
bun apps/worker/src/migrate.ts # what the Compose step runs
bun run db:migrate:all # the same, from a checkout每个专用数据库都通过其注册名称访问。名为 env:QUIRE_DB_NORTHWIND_URL 的数据库需要:
| 变量 | 用途 |
|---|---|
QUIRE_DB_NORTHWIND_URL |
应用角色,供 Web 层和 worker 使用 |
QUIRE_DB_NORTHWIND_URL_MIGRATOR |
迁移角色,供此命令和迁移操作使用 |
QUIRE_DB_NORTHWIND_URL_SUPERUSER |
可选:迁移前重新应用启动配置(角色、模式、辅助函数) |
未配置 _MIGRATOR 连接的已注册数据库会作为失败报告,绝不会跳过。控制数据库迁移完成后即可滚动升级 Web 层。落后一小时会发出警告,落后一天会触发告警。
pgvector
从迁移 0264 开始,只要服务器安装了扩展,语料检索就会使用 pgvector HNSW 索引;Compose 的 postgres 服务已通过 docker/postgres.Dockerfile 编译此扩展。切换镜像后的首次 migrate 会通过超级用户启动配置创建扩展,然后迁移 0264 会添加生成的向量列并构建索引。添加列时会在排他锁下重写一次 app.ai_chunk,因此检索请求会等待;没有其他表会受到影响。
未安装 pgvector 的服务器上,迁移 0264 会记录提示但不做任何更改,检索仍使用精确匹配。pgvector 版本低于 0.8 时,虽然会创建列和索引,检索仍使用精确匹配,直到扩展升级(运行 alter extension vector update),因为带筛选条件的 HNSW 扫描需要 0.8 提供的迭代扫描功能。若要在尚未安装扩展的服务器上稍后启用,请安装扩展、再次运行启动配置(或以超级用户身份运行 create extension vector),然后以 quire_migrator 身份执行:
set maintenance_work_mem = '1GB'; -- the HNSW build is much faster in memory
select ops.ai_chunk_enable_vector_index();该操作具有幂等性,会返回 enabled 或 unavailable。请在每个专用租户数据库中也运行此操作。
回滚
始终可以回滚代码:将 QUIRE_RELEASE 设为上一标签,再次运行 up -d。由于同一版本范围内的数据库模式双向兼容,因此此操作有效。
不提供数据库模式回滚。以下更改无法撤销;如果必须恢复,请按相应方式处理:
| 无法恢复的更改 | 恢复方式 |
|---|---|
| 收缩迁移删除了某列 | 将时间点恢复到删除之前的新数据库,提取数据并合并 |
| 原地更改数据 | 同上,然后协调恢复后产生的写入 |
| 已发送的 webhook 和事件 | 发送补偿事件,绝不删除 |
| 已发送的电子邮件 | 由人员撰写后续邮件 |
| 审计哈希链 | 永远不重写;追加更正记录 |
因此,收缩迁移会单独发布:之后若需恢复,就有一个清晰的时间边界。
检查升级结果
docker compose -f docker/compose.yaml ps # every service healthy
curl -fsS http://localhost:8080/readyz # ready, and what is configured
docker compose -f docker/compose.yaml logs migrate # the migrations applied