
bug: Multi-worker websocket delivery breaks: chat:completion events with embedded RAG sources can exceed Redis pubsub buffer limits (>32MB)
快速结论:当使用多 worker 架构(WEBSOCKET_MANAGER=redis),且模型回答中嵌入了大量 RAG 来源(sources)时,单个 chat:completion Socket.IO 事件可能超过 Redis 默认的 pub/sub 输出缓冲区限制(32MB),导致 Redis 强制断开所有订阅者连接,造成用户端流式响应中断且无法自动恢复。优先排查 Redis 的 client-output-buffer-limit pubsub 配置,以及 RAG 来源数据的体积。
问题场景
Open WebUI v0.9.6(及更新版本),采用 Docker Compose 部署,配置了 ENABLE_WEBSOCKET_SUPPORT=true、WEBSOCKET_MANAGER=redis、UVICORN_WORKERS=8 及基于 Redis/Valkey 的 Socket.IO 管理器。用户使用自定义模型,模型绑定了大量知识库文档(tens of MB),在提问后触发 RAG 检索并返回包含大量文档片段或搜索结果的事件负载。
报错原文
1:M 10 Jun 2026 20:51:58 # Client id=543906 … flags=P … cmd=subscribe …
omem=33554456 … scheduled to be closed ASAP for overcoming of output buffer limits.
在 Redis/Valkey 日志中可以看到 Pub/Sub 订阅者因超出默认输出缓冲区限制(client-output-buffer-limit pubsub 32mb 8mb 60)而被强制关闭。
原因分析
chat:completion 事件在 emit 时,会将完整的 RAG sources/citations 负载(包含文档全文)嵌入其中,且没有大小限制。当自定义模型附加的大型知识库或网络搜索结果触发大量分块返回时,单次事件可能达到约 33MB。该事件通过 Redis pub/sub 通道扇出(fan-out)到全部 8 个 worker,但 Redis 默认的 Pub/Sub 输出缓冲区硬限制为 32MB,导致所有订阅者连接被 Redis 强制关闭。部分 worker 的 pub/sub 监听器在断连后未能自动恢复(受限于 python-socketio 的重试机制,参见 miguelgrinberg/python-socketio#1581),造成该 worker 永久“失聪”——其 Docker 健康检查保持正常,但约 1/8 的 WebSocket 连接再也收不到聊天事件。受影响用户的后端实际上完成了回答生成并持久化(done: true,已计费),但因 WebSocket 推送中断,浏览器收不到任何数据块,UI 陷入无限等待,且由于 WebSocket-only 模式(transports=['websocket']),没有 SSE 或轮询回退机制,用户只能手动刷新页面才能看到已保存的回答。
环境排查
- 确认 Open WebUI 版本(复现版本 v0.9.6,但后续版本也存在此问题)。
- 确认
UVICORN_WORKERS是否大于 1(多 worker 才会扇出)。 - 确认
WEBSOCKET_MANAGER是否为redis。 - 确认 Redis/Valkey 的
client-output-buffer-limit pubsub配置(默认值为32mb 8mb 60)。 - 检查模型关联的知识库文档总大小及单次检索返回的分块数量。
- 检查
PUBSUB NUMSUB socketio的值是否持续低于 worker 数量(表示有 worker 失聪)。 - 查看 Redis/Valkey 日志中是否有
overcoming of output buffer limits关键字。
解决步骤
- 临时缓解(立即生效): 调整 Redis/Valkey 的 Pub/Sub 输出缓冲区限制,增大硬限制和软限制。例如在 Redis 配置文件或通过
CONFIG SET命令设置:client-output-buffer-limit pubsub 128mb 64mb 120。提高限制仅推迟触发临界点,而非根治。 - 根本修复(推荐): 关注上游修复。根据 Issue 讨论,该问题的根因在于
chat:completion事件嵌入了完整的累积负载和 sources 数据。建议:- 将 RAG sources 从事件负载中剥离,改用引用 ID 或分页方式传输。
- 或对 sources 负载实施大小上限(cap),超出部分截断或分片发送。
- 相关修复已在 Open WebUI 后续版本的开发计划中(可参阅关联 Issue #23733 的增量传输优化思路)。
- 监控与恢复: 如果遇到 worker 失聪(
NUMSUB < workers),可配置定期检查并自动重启失聪 worker 的容器。 - 作为备选方案: 如果无法立即优化负载大小,可考虑减少
UVICORN_WORKERS数量以降低扇出放大效应,但这会降低并发处理能力。
验证方法
- 在触发大 RAG 负载的对话后,检查 Redis/Valkey 日志,确认不再出现
overcoming of output buffer limits消息。 - 执行
PUBSUB NUMSUB socketio确认其数值等于 worker 数量。 - 让多个用户同时触发包含大量 RAG 来源的查询,确认所有流式响应均可正常到达浏览器,不会出现“回答已保存但 UI 一直等待”的情况。

![[Claude] [开源] CCL:我做了一个 Claude Code 启动器,把 ccswitch 干掉了](https://www.chat-gpts.plus/wp-content/uploads/2026/06/ai_cover_3-595-768x403.jpg)
![[推广] 阿里腾讯华为火山国内国际站 AWS/GCP 全部 7 折 CDN4000/P Ai 模型低至 2 折](https://www.chat-gpts.plus/wp-content/uploads/2026/06/ai_cover_2-596-768x403.jpg)
