扩展 OPL 数据空间
OPL 数据空间从单用户到面向企业与机构的大规模组织化部署,都可以平滑扩展。下面这份指南会说明,当使用规模变大时,应该如何逐步调整部署方式。
OPL 数据空间采用无状态、容器优先架构,因此它的扩展方式与现代 Web 应用非常相似。无论你是从个人玩具环境走向部门级部署,还是从几百用户继续扩展到上千用户,核心积木都是同一组。
本文会从高层角度讲清楚关键概念和配置。确切的环境变量细节请看 环境变量参考。
如果你的部署启用了组织,扩缩容工作应与租户感知检索、文件归属和管理作用域行为一起规划,而不是简单当成纯基础设施改造。
面向组织化部署的扩容前检查
在增加副本、worker 或外部向量数据库之前,先验证租户模型:
- 阅读 组织,明确哪些资源属于组织,哪些属于平台全局。
- 阅读 管理作用域,确保运维人员理解某个设置是在
Global下生效,还是对当前选中的组织生效。 - 在任何可能触发维护模式、Qdrant payload 迁移或租户修复流程的上线之前,先看 组织维护。
- 在引入并发之前,确认共享存储、向量数据库和迁移姿态已经准备好。带着尚未解决的租户漂移问题去扩容,只会让恢复更困难。
理解默认配置
开箱即用时, OPL 数据空间以单容器方式运行,并具备:
- 一个保存在本地卷上的 内置 SQLite 主数据库
- 一个同样基于 SQLite 的 内置 ChromaDB 向量数据库
- 一个 Uvicorn worker
- 没有外部依赖,即没有 Redis、也没有外部 DB
这对个人使用、小团队试用和功能评估很合适。当你超出这些默认值时,就进入了扩容路径。关键点在于:如果你要安全地运行多个进程,那么主数据库和向量数据库这两个 SQLite 都必须被替换。
步骤 1:切换到 PostgreSQL
适用时机: 你打算运行多个 OPL 数据空间实例,或者需要更好的数据库性能与可靠性。
SQLite 把所有东西存进一个文件里,不适合多个进程并发写入。PostgreSQL 是生产级数据库,可以支撑大量并发连接。
你需要做的事:
把 DATABASE_URL 指向你的 PostgreSQL:
DATABASE_URL=postgresql://user:password@db-host:5432/openwebui关键点:
- OPL 数据空间不会自动在数据库之间迁移数据,所以不要等 SQLite 里已经有很多生产数据后才临时决定切换。
- 高并发部署要调优
DATABASE_POOL_SIZE和DATABASE_POOL_MAX_OVERFLOW。 - 每个 OPL 数据空间实例都有自己独立的连接池,总连接数 = 每实例连接池大小 × 实例数。
- 如果跳过这一步直接在 SQLite 上跑多个实例,你大概率会遇到
database is locked和数据损坏。
一个常见起点是 DATABASE_POOL_SIZE=15 与 DATABASE_POOL_MAX_OVERFLOW=20,但总连接数仍应明显低于 PostgreSQL 的 max_connections。
为什么网络存储上的 SQLite 一扩容就会出事
从 0.9.0 开始, OPL 数据空间的后端数据层已经完全异步化。异步带来了更高并发,但也把原本“在 NFS / CephFS / Azure Files 上只是慢”的 SQLite,变成了“升级后直接卡死”的高风险组合。
原因很直接:
- SQLite 每次提交都要
fsync() - 本地 SSD 上这个成本很低,但网络存储上可能高出几百到几千倍
- 异步后端会同时调度大量数据库协程
- 慢
fsync会长时间占住连接 - 连接池很快被打满,随后整个应用开始超时、阻塞甚至失效
因此没有什么参数能真正“修好”运行在网络存储上的 SQLite。可行路径只有三条:
- 最佳方案:切到 PostgreSQL。
- 把
webui.db挪到本地 SSD/NVMe。 - 临时止血:
DATABASE_POOL_SIZE=1
DATABASE_SQLITE_PRAGMA_BUSY_TIMEOUT=30000第三种只是用串行化换稳定,不适合长期使用。
步骤 2:加入 Redis
适用时机: 你要运行多个 OPL 数据空间实例,或者一个实例内启用多个 Uvicorn worker。
Redis 会作为共享状态存储,帮助所有实例协调会话、WebSocket 连接与应用状态。如果没有它,不同请求落到不同实例时,用户会看到不一致行为。
需要设置的典型变量:
REDIS_URL=redis://redis-host:6379/0
WEBSOCKET_MANAGER=redis
ENABLE_WEBSOCKET_SUPPORT=true没有 Redis 的多实例部署常见问题包括:
- WebSocket 403
- 配置不同步
- 登录状态和认证间歇性异常
步骤 3:运行多个实例
适用时机: 你需要承载更多用户,或者想要高可用。
OPL 数据空间是无状态的,因此可以放在 负载均衡器 后面运行多个相同副本。
在运行多实例之前,先完成 PostgreSQL 和 Redis。另外,所有副本必须共享同一个 WEBUI_SECRET_KEY,否则会出现登录循环和 401。
方案 A:容器编排(推荐)
使用 Kubernetes、Docker Swarm 等编排平台:
- 每个容器保持
UVICORN_WORKERS=1 - 除一个专门负责迁移的主副本外,其余副本都设置
ENABLE_DB_MIGRATIONS=false - 通过调整副本数来扩缩容
方案 B:单容器多 worker
如果只是单机但机器性能足够,可以提高:
UVICORN_WORKERS=4不过即便这样,你仍然需要 PostgreSQL 和 Redis。
容器编排通常更推荐,因为它天然支持重启、滚动更新和更细粒度的资源控制。
步骤 4:切换到外部向量数据库
适用时机: 只要你运行多个 worker,或者多个副本,这一步就是必须的。
默认的 ChromaDB 使用本地 SQLite 支撑,SQLite 连接不具备 fork-safe 特性。多个 worker 或副本并发访问时,最常见后果就是文档上传时 worker 直接崩掉。
你需要做的事:
VECTOR_DB=pgvector常见替代方案:
| 向量数据库 | 适合场景 |
|---|---|
| PGVector | 已经在用 PostgreSQL,想复用现有数据库设施 |
| MariaDB Vector | 需要 HNSW 搜索与更好的多连接扩展能力 |
| Milvus | 大规模高吞吐自托管场景 |
| Qdrant | 强过滤和元数据检索场景 |
| Pinecone | 托管式云服务 |
| ChromaDB HTTP 模式 | 仍想用 Chroma,但把它独立部署成单独服务 |
如果你已经因为主数据库使用了 PostgreSQL,那么 PGVector 往往是最简单的选择。
步骤 5:让多个实例共享文件存储
适用时机: 多个实例需要共享上传文件、生成图片和其他用户数据时。
默认情况下, OPL 数据空间会把上传文件写到本地文件系统的 DATA_DIR。在多实例部署下,所有副本都必须能访问同一批文件,否则请求打到别的副本时,文件或知识库就会“消失”。
你有两种主流方案:
| 方案 | 适合场景 |
|---|---|
| 共享文件系统(NFS、EFS、CephFS、共享卷) | 最简单,适合大多数自建部署 |
| 对象存储(S3、GCS、Azure Blob) | 更适合云原生和更大规模的环境 |
STORAGE_PROVIDER 只影响上传文件存储位置,不影响主数据库或向量数据库。
不要把 SQLite 主数据库放在网络文件系统上。这再次说明,想扩容就应该先切到 PostgreSQL。
对象存储配置示例:
STORAGE_PROVIDER=s3
S3_BUCKET_NAME=my-openwebui-bucket
S3_REGION_NAME=us-east-1步骤 6:修正内容提取与 Embedding 默认值
适用时机: 你在生产 环境中经常处理文档、知识库和 RAG。
默认的内容提取器 pypdf 与默认 embedding 引擎 SentenceTransformers,是生产环境内存泄漏和占用失控的两大常见来源。
推荐改法:
- 把内容提取切到外部服务:
CONTENT_EXTRACTION_ENGINE=tika
TIKA_SERVER_URL=http://tika:9998- 把 embedding 切到外部 provider:
RAG_EMBEDDING_ENGINE=openai
# 或自托管
RAG_EMBEDDING_ENGINE=ollama这样做的原因:
pypdf的内存泄漏会让 OPL 数据空间进程持续涨内存SentenceTransformers每个 worker 都可能吃掉数百 MB 内存- 把这两块移到外部服务,可以把泄漏和大模型加载成本从主应用进程中隔离出去
步骤 7:加入可观测性
适用时机: 你需要监控性能、排障并理解大规模部署行为。
OPL 数据空间支持 OpenTelemetry:
ENABLE_OTEL=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://your-collector:4317这可以帮助你观察请求延迟、数据库查询性能、错误率等关键指标。
组合后的生产级部署形态
一个较完整的生产级扩展部署,通常会包含:
- 负载均衡器
- 多个无状态 WebUI 副本
- PostgreSQL(可带 PGVector)
- Redis
- 共享文件存储(NFS 或 S3)
如果继续放大规模,还应同时配套:
- 外部内容提取服务
- 外部 embedding 服务
- OpenTelemetry 观测体系
扩容部署的最小环境变量集合
# Database
DATABASE_URL=postgresql://user:password@db-host:5432/openwebui
# Vector DB
VECTOR_DB=pgvector
PGVECTOR_DB_URL=postgresql://user:password@db-host:5432/openwebui
# Redis
REDIS_URL=redis://redis-host:6379/0
WEBSOCKET_MANAGER=redis
ENABLE_WEBSOCKET_SUPPORT=true
# Content extraction
CONTENT_EXTRACTION_ENGINE=tika
TIKA_SERVER_URL=http://tika:9998
# Embeddings
RAG_EMBEDDING_ENGINE=openai
# Workers
UVICORN_WORKERS=1
# Migrations
ENABLE_DB_MIGRATIONS=false快速判断:什么场景需要什么组件
| 场景 | PostgreSQL | Redis | 外部向量 DB | 外部内容提取 | 外部 Embeddings | 共享存储 |
|---|---|---|---|---|---|---|
| 单用户 / 评估环境 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
| 小团队,单实例 | 建议 | 建议 | ✗ | 建议 | ✗ | ✗ |
| 多 Uvicorn worker | 必须 | 必须 | 必须 | 强烈建议 | 强烈建议 | 同机文件系统即可 |
| 多实例 / 高可用 | 必须 | 必须 | 必须 | 强烈建议 | 强烈建议 | 需要 |
| 大规模(1000+ 用户) | 必须 | 必须 | 必须 | 强烈建议 | 强烈建议 | 需要 |
短结论:
- 想扩到多进程、多副本,先把两套 SQLite 都换掉
- 想稳定跑 RAG,不要继续依赖默认提取器和默认 embedding
- 想让多副本行为一致,Redis 和共享存储都不能缺