单Collection、每租户独立Collection与分片键怎么选?向量数据库多租户架构完整指南
发布时间:2026/8/7 9:59:32 作者:尧图编辑部 阅读量:1,286

文章摘要企业RAG平台从单客户扩展到数百、数千甚至数万个租户后向量数据库必须回答一个核心问题不同租户的数据应该放在同一个Collection中通过Payload过滤隔离还是每个租户建立独立Collection或者使用自定义分片键、分层多租户和“大租户独立、小租户共享”的混合方案这个决定会影响内存、索引数量、过滤性能、热点隔离、备份恢复、合规边界、租户删除和未来迁移。如果过早采用每租户一个Collection可能产生海量小索引和运维负担如果所有数据永远放在一个共享Collection又可能出现过滤性能下降、热点租户互相影响和迁移困难。本文从Qdrant、Milvus、pgvector等系统都适用的通用原则出发详细分析三类架构的实现方式、成本模型、适用边界和迁移路径并给出可落地的Tenant Placement目录、在线迁移、双写和数据一致性设计。一、为什么多租户向量库不能只讨论“隔离”传统关系数据库的多租户架构通常比较共享表 独立Schema 独立数据库向量数据库还要额外考虑HNSW等索引的固定开销每个Collection的Segment数量Payload过滤选择性ANN搜索是否能利用过滤条件向量维度与存储Embedding重建成本热点租户对缓存和CPU的影响Collection创建和优化时间分片数量与副本租户迁移时的重建成本。因此“隔离越强越好”并不成立。一个拥有100个大型企业客户的系统和一个拥有10万个小团队的SaaS平台最优方案完全不同。二、三种核心架构方案一共享CollectionPayload过滤所有租户放在同一Collectioncollection: enterprise_knowledge每个Point/Chunk携带{tenant_id:T001,document_id:D1001,status:EFFECTIVE,knowledge_base_id:KB01}查询必须带tenant_id T001数据布局enterprise_knowledge ├── T001 chunks ├── T002 chunks ├── T003 chunks └── ...优势Collection数量少索引和Segment固定开销低资源利用率高新租户无需创建基础设施小租户可以共享索引和缓存统一备份和监控适合大量长尾小租户。风险过滤条件错误会造成跨租户泄露高基数租户字段需要合理索引大租户可能占用大量缓存和CPU删除单租户数据需要精准过滤单Collection故障影响范围大单租户独立恢复更困难全局索引参数难以适配所有租户。三、共享Collection适合什么场景推荐条件租户数量多 单租户数据量相对小 隔离以逻辑权限为主 查询总是带tenant过滤 平台有成熟权限测试典型场景SaaS知识助手中小企业文档问答大量项目空间用户个人知识库单租户几千到几十万Chunk租户生命周期频繁创建和删除。四、共享Collection必须补齐哪些能力1. tenant_id元数据索引所有高频过滤字段建立Payload或元数据索引。2. 强制查询守卫业务不能直接调用VectorStore。publicinterfaceTenantScopedVectorStore{ListDocumentsimilaritySearch(AccessContextaccess,TenantSearchRequestrequest);}3. 缓存隔离Key必须包含tenant_id permission_hash index_version query4. 数据完整性约束每个Chunk必须包含tenant_iddocument_idstatusversion。5. 越权测试持续执行跨租户蜜罐查询。6. 热点治理按租户统计QPS向量数量查询延迟CPU缓存命中写入速率。达到阈值后可迁移到独立分片或Collection。五、方案二每租户独立Collection每个租户拥有自己的Collectiontenant_T001_knowledge tenant_T002_knowledge tenant_T003_knowledge优势数据边界直观查询无需tenant过滤单租户删除简单单租户备份和恢复更容易可设置独立索引参数大客户性能更可控合规和专属资源表达更清晰租户迁移可独立执行。风险Collection数量可能爆炸每个Collection有索引和Segment开销大量小Collection浪费内存创建、优化、备份和监控复杂元数据变更需要批量操作平台升级要处理海量对象查询路由依赖准确的Collection目录跨租户共享知识更难。六、为什么“每租户一个Collection”容易被高估开发者常认为Collection独立 绝对安全但安全仍取决于路由。如果代码Stringcollectionrequest.getTenantId();仍可能查询错误Collection。每租户Collection只降低了过滤逻辑错误风险并没有替代身份认证租户归属校验Collection路由目录缓存隔离引用鉴权运维权限。同时海量小Collection可能比一个共享Collection更难维护。七、独立Collection适合什么场景推荐条件租户数量较少 单租户数据量大 需要独立备份恢复 需要定制索引 需要强资源隔离典型场景少量大型企业客户专属实例或专属资源套餐租户数几十到数百单租户数千万向量监管要求独立恢复每个租户Embedding维度或距离算法不同大客户有明显性能SLA。八、方案三自定义分片键或分区在一个逻辑Collection中通过分片键将租户路由到特定Shard。概念collection: enterprise_knowledge shared shard: 小租户A/B/C/D dedicated shard T100: 超大租户T100 dedicated shard T200: 热点租户T200查询时同时提供tenant payload filter shard key selector优势保留统一Collection管理大租户可独立Shard查询只访问目标Shard热点隔离小租户仍共享资源支持租户晋升更适合租户规模差异显著的系统。风险需要维护Tenant→Shard映射分片数量不能无限增长迁移过程复杂双写和一致性要求高不同数据库能力差异较大运维与容量规划要求更高。九、为什么分片键不能直接使用所有tenant_id如果有10万个租户就创建10万个物理Shard通常不可行。物理Shard有元数据-副本Segment调度Raft或一致性开销内存运维对象。因此应区分逻辑租户分区 与 物理Shard大量小租户更适合Payload分区少量大型租户才适合专用Shard。十、方案四分层混合架构实际生产中最常见的最优方案小租户 → 共享Collection/共享Shard 中型租户 → 指定共享Shard组 大型或高SLA租户 → 独立Shard或独立Collection 监管专属租户 → 独立集群这是一种“租户放置策略”。租户层级publicenumTenantVectorTier{SHARED,GROUPED,DEDICATED_SHARD,DEDICATED_COLLECTION,DEDICATED_CLUSTER}放置记录publicrecordTenantVectorPlacement(StringtenantId,TenantVectorTiertier,StringclusterId,StringcollectionName,StringshardKey,StringembeddingProfile,StringplacementVersion,PlacementStatusstatus){}业务查询不能自己拼Collection名称必须通过Placement Service。十一、统一Tenant Placement ServiceServicepublicclassTenantVectorPlacementService{privatefinalTenantPlacementRepositoryrepository;publicTenantVectorPlacementrequire(StringtenantId){TenantVectorPlacementplacementrepository.findActiveByTenantId(tenantId).orElseThrow(()-newMissingPlacementException(tenantId));if(placement.status()!PlacementStatus.ACTIVE){thrownewPlacementNotReadyException(tenantId,placement.status());}returnplacement;}}检索器publicListDocumentsearch(AccessContextaccess,Stringquery){TenantVectorPlacementplacementplacementService.require(access.tenantId());VectorStorevectorStorevectorStoreRegistry.require(placement.clusterId(),placement.collectionName());SearchRequestrequestsearchRequestFactory.create(query,access,placement);returnvectorStore.similaritySearch(request);}十二、三种方案的详细对比维度共享Collection每租户Collection分片/混合租户创建速度最快需创建对象取决于Tier小租户资源效率高低高大租户性能隔离弱到中强强权限依赖高度依赖过滤依赖路由过滤路由Collection数量少多中索引参数定制全局每租户按Shard/Collection单租户备份恢复较难容易中到容易单租户删除过滤删除删除Collection按Shard/过滤热点迁移较难容易设计目标运维复杂度低高中高适合租户规模大量小租户少量大租户规模差异大物理隔离表达弱中强可分层故障影响范围较大单Collection可控成本最低较高平衡十三、容量模型怎么估算不能只看向量数量。需要估算向量原始存储 向量索引 Payload Payload索引 副本 Segment开销 缓存 增长冗余向量原始大小近似向量数量 × 维度 × 每维字节数例如1000万向量 × 1536维 × 4字节 ≈ 61.44 GB这还没有包括HNSWPayload副本WALSegment元数据压缩差异。为每租户建立独立Collection时还要计算每个小索引的固定开销。十四、过滤选择性为什么重要共享Collection查询tenant_id T001如果T001只有全库的0.001%过滤选择性很高。向量数据库需要能在过滤条件下有效搜索否则可能扫描大量无关候选延迟波动Recall下降CPU升高。因此需要tenant_id索引合理HNSW过滤配置查询始终带tenant过滤对大租户考虑专用分区真实规模压测。不要只用几千向量的开发环境判断架构。十五、租户删除怎么设计共享Collection执行delete where tenant_id T001风险条件错误扩大删除删除耗时Segment回收延迟备份中仍存在派生缓存和引用未清理。需要删除任务publicrecordTenantDeletionJob(StringjobId,StringtenantId,StringplacementVersion,DeletionStatusstatus,longexpectedVectorCount,longdeletedVectorCount){}独立Collection可以删除整个Collection但仍要清理数据库记录对象存储-缓存备份审计保留Placement记录连接池。十六、单租户备份与恢复共享Collection中恢复单租户通常更复杂从备份恢复临时集群 ↓ 筛选租户数据 ↓ 写回生产 ↓ 校验版本独立Collection可以直接恢复Collection。因此如果合同明确要求单租户RPO/RTO需要把恢复成本纳入选型而不是只比较查询性能。十七、在线迁移小租户晋升为独立Shard当共享租户变成热点客户需要迁移。推荐状态机ACTIVE_SHARED ↓ MIGRATION_PREPARING ↓ DUAL_WRITE ↓ BACKFILL ↓ VERIFYING ↓ READ_SWITCH ↓ DRAINING_OLD ↓ ACTIVE_DEDICATED1. 创建目标PlacementTenantVectorPlacementtargetplacementFactory.dedicatedShard(tenantId);2. 开启双写新写入同时进入旧位置和新位置。3. 回填历史数据按文档版本和Chunk ID复制。4. 校验比较Point数量文档数量Checksum采样向量检索结果权限元数据索引状态。5. 切读Placement版本原子更新。6. 保留回滚窗口旧数据暂不删除。十八、双写的幂等设计Point ID必须稳定。推荐tenant_id logical_document_id document_version chunk_idHash为固定Point ID。publicUUIDpointId(StringtenantId,StringdocumentId,Stringversion,StringchunkId){returnUUID.nameUUIDFromBytes(String.join(|,tenantId,documentId,version,chunkId).getBytes(StandardCharsets.UTF_8));}双写重试不会产生重复向量。十九、迁移期间如何保证读取一致三种模式1. 旧读双写最安全的开始阶段。2. 新读旧读对比影子读取新位置比较结果但仍返回旧位置。3. 新读旧位置回滚验证通过后切换。不要在回填未完成时合并新旧查询结果容易产生重复Chunk和版本冲突。二十、Embedding配置不同怎么办不同Collection可能使用不同Embedding模型维度距离度量量化索引参数。Placement必须记录publicrecordEmbeddingProfile(StringprofileId,StringmodelId,intdimensions,DistanceMetricdistance,Stringnormalization,Stringversion){}查询必须使用与目标Collection一致的Embedding Profile。如果路由到错误Collection维度可能直接报错更危险的是维度相同但Embedding模型不同查询能执行却质量严重下降。二十一、跨租户共享知识怎么处理企业平台可能有平台公共知识 租户私有知识不要把公共知识复制到每个租户。可以设计公共Collection 租户Collection/分区查询公共知识检索 租户私有检索 ↓ 分别权限校验 ↓ 结果融合证据中明确scopePLATFORM_PUBLIC scopeTENANT_PRIVATE公共知识仍要版本化不能默认永久有效。二十二、选型决策树是否存在物理隔离或独立集群要求 ├─ 是独立Collection或独立集群 └─ 否继续 租户数量是否很多且大多数租户较小 ├─ 是共享CollectionPayload过滤 └─ 否继续 租户数据规模和QPS差异是否很大 ├─ 是分层混合大租户专用Shard └─ 否继续 是否要求单租户独立备份恢复或索引参数 ├─ 是独立Collection └─ 否共享Collection 未来是否可能出现超级租户 ├─ 是从第一天建立Tenant Placement和在线迁移能力 └─ 否仍建议保留Placement抽象二十三、不同规模的推荐方案100个大型租户每租户独立Collection 或 少量租户共享大型租户独立1万个中小租户共享Collection tenant Payload索引 热点租户晋升机制100万个个人空间共享Collection/分区 禁止每用户独立Collection 强制查询守卫 缓存与权限哈希强监管客户独立Collection 独立密钥 独立备份 必要时独立集群二十四、生产检查清单□ 已统计租户数量与未来增长 □ 已统计单租户向量分布而不只看平均值 □ 已明确物理隔离和恢复要求 □ 共享Collection查询强制tenant过滤 □ tenant_id已建立Payload/元数据索引 □ Tenant Placement是统一真相源 □ 业务代码不拼Collection名称 □ Placement记录Embedding Profile □ 大租户有晋升阈值 □ 在线迁移具备双写、回填和验证 □ Point ID稳定且双写幂等 □ 缓存Key包含Placement版本 □ 单租户删除和恢复经过演练 □ 公共知识与租户私有知识分开治理 □ 已按真实规模测试过滤延迟与Recall总结多租户向量库没有一个适合所有规模的固定答案共享Collection 适合大量小租户和资源复用 每租户Collection 适合少量大租户、强隔离和独立恢复 分片键与混合架构 适合租户规模差异大、需要热点晋升的平台最重要的不是今天选哪一种而是从一开始建立Tenant Placement目录 稳定Point ID 权限查询守卫 分层容量指标 在线迁移能力这样系统才能在客户规模变化时从共享平滑晋升到专用资源而不是被早期Collection命名方式永久锁死。