多副本、高可用与并发排障
本页针对 多副本部署(Kubernetes、Docker Swarm)以及 多 worker(UVICORN_WORKERS > 1)场景下的常见问题。
如果你是第一次做扩容部署,建议先读 Scaling OPL 数据空间。
基础要求清单
多副本场景里,下面这些是硬要求:
- 共享密钥:所有副本的
WEBUI_SECRET_KEY必须完全一致 - 外部数据库:必须使用 PostgreSQL,SQLite 不支持多实例共享
- Redis WebSocket:启用
ENABLE_WEBSOCKET_SUPPORT=True、WEBSOCKET_MANAGER=redis和有效的WEBSOCKET_REDIS_URL - 共享存储:
data/至少要保证上传文件、RAG 与图片生成能在各副本间一致可见 - 外部向量库:默认本地 ChromaDB 基于 SQLite,不适合多 worker / 多副本
- 可选的数据库会话共享: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 广播跨副本事件
解决:
- 配好
CORS_ALLOW_ORIGIN - 所有副本都启用 Redis WebSocket:
ENABLE_WEBSOCKET_SUPPORT=True
WEBSOCKET_MANAGER=redis
WEBSOCKET_REDIS_URL=redis://your-redis-host:6379/03. 模型找不到 / 配置不同步
现象:
- 你在某个副本改了模型配置,其他副本看不到
- 刷新后偶发 “Model not found”
原因:
缺少 REDIS_URL,导致配置变更无法通过 Pub/Sub 在副本间广播。
解决:
REDIS_URL=redis://your-redis-host:6379/04. 数据库锁 / 池耗尽 / SQLite 崩溃
现象:
database is lockedQueuePool limit reached- 升级后
/api/config、聊天列表、OIDC 回调都明显卡死
原因:
多副本场景下使用 SQLite,或者把 webui.db 放在网络文件系统上。SQLite 的锁模型在这类环境下并不可靠,0.9.x 之后更容易放大成硬故障。
解决顺序:
- 迁移到 PostgreSQL,这是正确答案
- 单实例且暂时不能迁移时,把 SQLite 放到本地 SSD / NVMe
- 不要指望只调大
DATABASE_POOL_SIZE - 临时止血时才考虑:
DATABASE_POOL_SIZE=1
DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT=30000