跳转到内容

无停机升级

在自托管环境中无停机升级 Quire。

相关规则见 docs/architecture/23-ops.md 第 7 节和 docs/architecture/07-data.md 第 4.1 节。此处介绍具体流程。

安全升级的保证

**版本 R 可以正确使用架构 R 和 R 减 1 的数据库模式。**每项数据库模式变更都分为扩展、过渡和收缩三个阶段:

  1. 扩展:添加新列、表或索引。旧代码会忽略它。
  2. 过渡:至少持续一个版本;新代码同时写入两种结构,并读取新结构;可续跑的任务会回填旧行。
  3. 收缩:在后续版本中单独移除旧结构。

因此,在滚动升级的任何时刻,新旧进程都可以共用同一个数据库。系统没有向下迁移:如果迁移在一小时前删除了某列,就无法恢复这一小时内写入的数据。

每个版本的 schema-compat CI 任务都会用新版数据库模式运行上一版本的测试,以检查这一保证。

开始之前

  1. 阅读版本说明。需要维护窗口的版本会明确说明,并估算所需时长;每个版本最多只有一次这样的发布。
  2. 执行恢复演练,或确认此版本的演练已成功(见 backup-restore.md)。演练失败会阻止升级。
  3. 创建基础备份: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

此顺序是有意安排的:

  1. 先迁移,旧版本仍在处理流量时执行。扩展迁移对旧版本不可见。
  2. 然后升级 Web 层。收到 SIGTERM 后,每个 Web 进程会将 /readyz 状态设为 draining,在 30 秒内完成正在处理的请求,以重连提示关闭流,然后退出。stop_grace_period 为 40 秒,因此 Compose 不会中断正常的退出过程。
  3. 最后升级 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
导航

输入以搜索…

↑↓ 导航↵ 选择Esc 关闭