跳到主要内容

多副本、高可用与并发排障

本页针对 多副本部署(Kubernetes、Docker Swarm)以及 多 workerUVICORN_WORKERS > 1)场景下的常见问题。

如果你是第一次做扩容部署,建议先读 Scaling OPL 数据空间

基础要求清单

多副本场景里,下面这些是硬要求:

  1. 共享密钥:所有副本的 WEBUI_SECRET_KEY 必须完全一致
  2. 外部数据库:必须使用 PostgreSQL,SQLite 不支持多实例共享
  3. Redis WebSocket:启用 ENABLE_WEBSOCKET_SUPPORT=TrueWEBSOCKET_MANAGER=redis 和有效的 WEBSOCKET_REDIS_URL
  4. 共享存储data/ 至少要保证上传文件、RAG 与图片生成能在各副本间一致可见
  5. 外部向量库:默认本地 ChromaDB 基于 SQLite,不适合多 worker / 多副本
  6. 可选的数据库会话共享:PostgreSQL 并发较高时,可考虑 DATABASE_ENABLE_SESSION_SHARING=True

组织感知部署额外提醒

如果启用了组织,多副本上线不仅是基础设施变更,也是租户边界变更:

  • 共享存储还不够,文件归属和向量归属也必须同步
  • 至少要验证一次 Global 和某个真实组织的生效配置
  • 如果近期做过租户迁移或拆分,先修完 repair 状态再放业务流量

常见问题

1. 登录循环 / 401

现象:

  • 登录成功后下一步又被踢出
  • 浏览器控制台出现 401 / Unauthorized
  • 日志里有 “Error decrypting tokens”

原因:

不同副本使用了不同的 WEBUI_SECRET_KEY。一个副本签发的 JWT 到另一个副本上验签失败。

解决:

所有副本统一设置同一个强随机 WEBUI_SECRET_KEY

2. WebSocket 403 / 连接失败

现象:

  • 聊天不再继续生成
  • 控制台出现 WebSocket connection failed
  • 日志提示 origin 不被接受

原因:

  • CORS_ALLOW_ORIGIN 配置不完整
  • WebSocket 还在用内存模式,没有借助 Redis 广播跨副本事件

解决:

  1. 配好 CORS_ALLOW_ORIGIN
  2. 所有副本都启用 Redis WebSocket:
ENABLE_WEBSOCKET_SUPPORT=True
WEBSOCKET_MANAGER=redis
WEBSOCKET_REDIS_URL=redis://your-redis-host:6379/0

3. 模型找不到 / 配置不同步

现象:

  • 你在某个副本改了模型配置,其他副本看不到
  • 刷新后偶发 “Model not found”

原因:

缺少 REDIS_URL,导致配置变更无法通过 Pub/Sub 在副本间广播。

解决:

REDIS_URL=redis://your-redis-host:6379/0

4. 数据库锁 / 池耗尽 / SQLite 崩溃

现象:

  • database is locked
  • QueuePool limit reached
  • 升级后 /api/config、聊天列表、OIDC 回调都明显卡死

原因:

多副本场景下使用 SQLite,或者把 webui.db 放在网络文件系统上。SQLite 的锁模型在这类环境下并不可靠,0.9.x 之后更容易放大成硬故障。

解决顺序:

  1. 迁移到 PostgreSQL,这是正确答案
  2. 单实例且暂时不能迁移时,把 SQLite 放到本地 SSD / NVMe
  3. 不要指望只调大 DATABASE_POOL_SIZE
  4. 临时止血时才考虑:
DATABASE_POOL_SIZE=1
DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT=30000

5. 上传文件 / RAG 数据跨副本不可见

原因:

/app/backend/data 没有真正共享,或者共享层不一致。

解决:

  • Kubernetes:使用支持 ReadWriteMany 的 PVC
  • Docker:所有容器挂同一个共享卷

6. 文档上传时 worker 直接崩

原因:

默认 ChromaDB 通过本地 SQLite PersistentClient 工作,多 worker 下会触发 fork 后共享 SQLite 连接的问题。

解决:

  • 保持 UVICORN_WORKERS=1
  • 或把 Chroma 改成 HTTP 模式
  • 或直接换成 pgvectorqdrantmilvus 等真正的外部向量库

7. 云上性能远差于本地

优先怀疑数据库网络延迟和磁盘 I/O 延迟,而不是单纯算力不足。详见 Performance

8. 数据库性能优化

PostgreSQL 下可以考虑:

  • DATABASE_ENABLE_SESSION_SHARING=true
  • 按数据库 max_connections 合理调整 DATABASE_POOL_SIZE
  • 记住总连接数会随着 副本数 × worker 数 一起放大

9. Function / Tool 运行时装依赖导致崩溃

多 worker / 多副本下,如果 frontmatter 里定义 requirements,多个进程可能同时执行 pip install,从而互相打架。

建议:

ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS=False

然后把依赖预装进镜像。


部署最佳实践

升级与迁移

数据库迁移只能让一个进程执行。最稳妥的方式:

  1. 指定一个 migration pod / 副本负责迁移
  2. 或者升级时先缩到 1 个副本且 UVICORN_WORKERS=1
  3. 等迁移完成并通过健康检查后,再扩回目标副本数

Sticky Sessions

虽然 OPL 数据空间 在正确使用 Redis 后可以做到近似无状态,但负载均衡层启用 sticky sessions 往往仍能减少 WebSocket 抖动。

相关文档