跳到主要内容

扩展 OPL 数据空间

OPL 数据空间从单用户到面向企业与机构的大规模组织化部署,都可以平滑扩展。下面这份指南会说明,当使用规模变大时,应该如何逐步调整部署方式。

OPL 数据空间采用无状态、容器优先架构,因此它的扩展方式与现代 Web 应用非常相似。无论你是从个人玩具环境走向部门级部署,还是从几百用户继续扩展到上千用户,核心积木都是同一组。

本文会从高层角度讲清楚关键概念和配置。确切的环境变量细节请看 环境变量参考

组织带来的不只是用户侧边界,也包括运维边界

如果你的部署启用了组织,扩缩容工作应与租户感知检索、文件归属和管理作用域行为一起规划,而不是简单当成纯基础设施改造。

面向组织化部署的扩容前检查

在增加副本、worker 或外部向量数据库之前,先验证租户模型:

  1. 阅读 组织,明确哪些资源属于组织,哪些属于平台全局。
  2. 阅读 管理作用域,确保运维人员理解某个设置是在 Global 下生效,还是对当前选中的组织生效。
  3. 在任何可能触发维护模式、Qdrant payload 迁移或租户修复流程的上线之前,先看 组织维护
  4. 在引入并发之前,确认共享存储、向量数据库和迁移姿态已经准备好。带着尚未解决的租户漂移问题去扩容,只会让恢复更困难。

理解默认配置

开箱即用时, 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_SIZEDATABASE_POOL_MAX_OVERFLOW
  • 每个 OPL 数据空间实例都有自己独立的连接池,总连接数 = 每实例连接池大小 × 实例数。
  • 如果跳过这一步直接在 SQLite 上跑多个实例,你大概率会遇到 database is locked 和数据损坏。
提示

一个常见起点是 DATABASE_POOL_SIZE=15DATABASE_POOL_MAX_OVERFLOW=20,但总连接数仍应明显低于 PostgreSQL 的 max_connections

为什么网络存储上的 SQLite 一扩容就会出事

从 0.9.0 开始, OPL 数据空间的后端数据层已经完全异步化。异步带来了更高并发,但也把原本“在 NFS / CephFS / Azure Files 上只是慢”的 SQLite,变成了“升级后直接卡死”的高风险组合。

原因很直接:

  • SQLite 每次提交都要 fsync()
  • 本地 SSD 上这个成本很低,但网络存储上可能高出几百到几千倍
  • 异步后端会同时调度大量数据库协程
  • fsync 会长时间占住连接
  • 连接池很快被打满,随后整个应用开始超时、阻塞甚至失效

因此没有什么参数能真正“修好”运行在网络存储上的 SQLite。可行路径只有三条:

  1. 最佳方案:切到 PostgreSQL。
  2. webui.db 挪到本地 SSD/NVMe。
  3. 临时止血:
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 数据空间是无状态的,因此可以放在 负载均衡器 后面运行多个相同副本。

注意

在运行多实例之前,先完成 PostgreSQLRedis。另外,所有副本必须共享同一个 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,是生产环境内存泄漏和占用失控的两大常见来源。

推荐改法:

  1. 把内容提取切到外部服务:
CONTENT_EXTRACTION_ENGINE=tika
TIKA_SERVER_URL=http://tika:9998
  1. 把 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

快速判断:什么场景需要什么组件

场景PostgreSQLRedis外部向量 DB外部内容提取外部 Embeddings共享存储
单用户 / 评估环境
小团队,单实例建议建议建议
多 Uvicorn worker必须必须必须强烈建议强烈建议同机文件系统即可
多实例 / 高可用必须必须必须强烈建议强烈建议需要
大规模(1000+ 用户)必须必须必须强烈建议强烈建议需要

短结论:

  • 想扩到多进程、多副本,先把两套 SQLite 都换掉
  • 想稳定跑 RAG,不要继续依赖默认提取器和默认 embedding
  • 想让多副本行为一致,Redis 和共享存储都不能缺