检索组件高效处理大量数据的能力是任何大规模高性能RAG系统的中枢。在处理数百万甚至数十亿向量时,单节点向量搜索方案不可避免地会遇到计算和内存的限制。分配和扩展向量搜索功能依赖于几种主要方法:将索引分片到多个节点上、复制数据以增加韧性和吞吐量,以及采用适合此类分布式环境的先进索引策略。基本难题:海量向量一个简单的单实例向量数据库在存储高维嵌入时最终会失效。主要限制有:内存 (RAM): 许多高性能的近似最近邻 (ANN) 索引,例如 HNSW 或 IVF_FLAT,在索引以及理想情况下向量本身驻留在内存中时,性能表现最佳。对于包含 1 亿个 768 维 float32 向量的数据集,仅原始向量数据就占用大约 286 GB (100e6 * 768 * 4 字节),这还不包括索引开销。这迅速超出了典型单台机器的容量。CPU: 计算查询向量与数百万或数十亿存储向量之间的距离(例如,余弦相似度、L2 距离)是计算密集型的。即使 ANN 算法显著缩小了搜索范围,随着每个节点的数据集增大,查询延迟也可能下降到不可接受的程度。I/O 吞吐量: 如果索引或向量部分存储在磁盘上,I/O 会成为瓶颈,特别是对于 RAG 系统中常见的读密集型工作负载。对于涉及频繁更新或添加的写密集型场景,I/O 限制更加明显。单点故障 (SPOF): 非分布式系统本质上是单点故障。任何硬件或软件故障都可能使整个检索功能无法使用。有效扩展向量搜索意味着通过分布式架构直接应对这些难题。分片:划分向量数据分片是将向量索引水平划分到多台机器或分片上的过程。每个分片持有总向量数据集的一个子集,并负责在其分配的分区内进行搜索。主要好处是分担数据存储负载和并行化查询执行。分片键选择与数据分布选择一个分片标准,即用于将向量分配给特定分片的标准,非常重要。常见策略有:对向量ID进行哈希: 对唯一向量标识符(例如,文档ID)进行一致哈希可以相对均匀地分配向量。分片数量通常是固定的,通过 shard_id = hash(vector_id) % num_shards 计算。基于范围的分片: 如果向量具有自然有序或可分段的ID,可以将范围分配给分片。如果数据分布不均,这有时会导致热点。基于元数据的分片: 向量可以根据相关元数据进行分片,例如多租户系统中的租户ID,或根据源数据特征。这可以改进某些查询模式的数据局部性,但需要仔细规划以避免不平衡。向量和查询负载在分片间的均匀分布是目标,以防止任何单个分片成为瓶颈。如果数据分布随时间显著变化,可能需要再平衡策略。分片环境中的查询路由当查询到达时,系统必须决定将其导向哪个或哪些分片:散射-收集(查询所有分片): 查询同时发送到所有分片。每个分片执行本地搜索,结果由协调节点或客户端汇总并重新排序。这种方法实现简单,对于最近邻可能位于任何位置的 ANN 搜索非常有效。但是,如果管理不当(例如,如果每个分片需要搜索 $k$ 个邻居,聚合器将获得 $N_{shards} \times k$ 个结果),它会使查询处理负载乘以分片数量。路由查询: 如果分片键可以从查询本身得出(例如,在特定租户的数据中搜索,并且租户 ID 是分片键),则查询可以直接路由到相关分片。这种方法效率更高,但对于通用语义搜索较少见。混合方法: 某些系统可能使用元数据来缩小查询的分片子集,然后在该子集中应用散射-收集。查询路由器或负载均衡器通常处理此逻辑,向应用程序隐藏索引的分片特性。复制:确保可用性和吞吐量复制涉及创建和维护每个分片的多个副本(如果未分片,则为整个索引)。它有两个主要目的:高可用性 (HA): 如果托管分片(或副本)的节点出现故障,其他副本可以继续提供请求服务,防止系统停机。提高读取吞吐量: 读取查询可以分发到分片的所有可用副本,显著提高系统处理并发请求的能力。复制模型与一致性常见复制模型有:主从复制: 写入操作发送到分片的指定主副本。主副本随后将更改传播到从副本。读取通常可以由从副本提供服务,但这可能涉及读取略微过时的数据(最终一致性)。对于强一致性,读取也可能需要发送到主副本或多数副本。多主/对等: 写入可以由多个副本接受,这需要冲突解决机制。这可以提供较低的写入延迟但增加了复杂性。对于 RAG 系统,向量索引可能定期批量更新,而非进行高频事务性写入,因此最终一致性通常是换取更高读取吞吐量和可用性的可接受权衡。可接受的过期时间窗口取决于应用程序对数据新鲜度的要求。分片与复制的结合使用分片与复制是互补的。典型的大规模部署涉及分片索引以实现可扩展性,然后复制每个分片以实现高可用性和提高读取吞吐量。例如,如果您有 3 个分片和 3 的复制因子,您将总共有 $3 \times 3 = 9$ 个节点(或进程)托管索引数据。下图展示了查询路由到分片、复制的向量索引分区的常见架构。digraph G { rankdir=LR; node [shape=box, style=rounded, fontname="Arial", fontsize=10]; edge [fontname="Arial", fontsize=9]; subgraph cluster_query_path { label = "查询路径"; style=filled; color="#e9ecef"; query_router [label="查询路由器/\n负载均衡器", shape=component, fillcolor="#a5d8ff"]; user_query [label="用户查询", shape=ellipse, fillcolor="#b2f2bb"]; } subgraph cluster_shards { label = "分布式向量索引分片"; style=filled; color="#dee2e6"; subgraph cluster_shard1 { label = "分片 1"; node [fillcolor="#ffec99"]; s1_leader [label="索引分区 1\n(主节点)"]; s1_replica1 [label="索引分区 1\n(副本)"]; s1_leader -> s1_replica1 [label="复制", dir=both, style=dashed, color="#495057"]; } subgraph cluster_shard2 { label = "分片 2"; node [fillcolor="#ffec99"]; s2_leader [label="索引分区 2\n(主节点)"]; s2_replica1 [label="索引分区 2\n(副本)"]; s2_leader -> s2_replica1 [label="复制", dir=both, style=dashed, color="#495057"]; } subgraph cluster_shardN { label = "分片 N (省略)"; graph[labeljust="c", labelloc="b"]; node [fillcolor="#ffec99"]; sN_leader [label="索引分区 N\n(主节点)"]; sN_replica1 [label="索引分区 N\n(副本)"]; sN_leader -> sN_replica1 [label="复制", dir=both, style=dashed, color="#495057"]; } } user_query -> query_router [color="#1c7ed6"]; query_router -> s1_leader [label="路由/散射", color="#1c7ed6"]; query_router -> s2_leader [label="路由/散射", color="#1c7ed6"]; query_router -> sN_leader [label="路由/散射", color="#1c7ed6"]; query_router -> s1_replica1 [style=dotted, label="读取", color="#0ca678"]; query_router -> s2_replica1 [style=dotted, label="读取", color="#0ca678"]; query_router -> sN_replica1 [style=dotted, label="读取", color="#0ca678"]; s1_leader -> query_router [label="结果", style=dashed, dir=back, color="#7048e8"]; s2_leader -> query_router [label="结果", style=dashed, dir=back, color="#7048e8"]; sN_leader -> query_router [label="结果", style=dashed, dir=back, color="#7048e8"]; }一个分片和复制的向量搜索架构。用户查询由路由器处理,路由器将搜索操作分发到分片的主节点或读取副本,随后汇总结果。用于规模化的先进索引结构尽管分片和复制分担了负载,但底层 ANN 索引算法的选择及其每个分片的配置对于性能和资源效率仍然非常重要。向量压缩:乘积量化存储数十亿个全精度浮点向量通常成本过高。乘积量化 (PQ) 及其变体,如 IVFADC(带有非对称距离计算的倒排文件系统),是高效的向量压缩技术,从而显著减少它们的内存占用。PQ 的工作原理是将每个向量划分为 $M$ 个子向量。然后,对于数据集中每组子向量,应用 k-means 聚类以创建 $k^$(通常为 256 个)质心。每个子向量随后被替换为其最近质心的 ID。一个 $D$ 维向量因此可以表示为 $M \times \log_2(k^)$ 位。例如,如果 $D=768$, $M=96$(每个子向量为 8 维),且 $k^*=256$,则每个子向量表示为 1 字节(8 位),因此整个向量为 96 字节,相对于 float32(768 * 4 = 3072 字节)实现了约 8 倍的压缩。{"data":[{"x":[1000000, 10000000, 100000000, 500000000],"y":[1.92,19.2,192,960],"type":"bar","name":"平面 (D=512, fp32)","marker":{"color":"#ff6b6b"}},{"x":[1000000, 10000000, 100000000, 500000000],"y":[0.064,0.64,6.4,32],"type":"bar","name":"IVFADC (M=64, D=512 -> 64 字节/向量)","marker":{"color":"#4dabf7"}},{"x":[1000000, 10000000, 100000000, 500000000],"y":[0.032,0.32,3.2,16],"type":"bar","name":"IVFADC (M=32, D=512 -> 32 字节/向量)","marker":{"color":"#51cf66"}}],"layout":{"title":{"text":"向量存储的估计内存占用 (GB)"},"xaxis":{"title":{"text":"向量数量 (原始 D=512, fp32)"},"type":"log", "tickfont":{"size":10}},"yaxis":{"title":{"text":"内存 (GB)"},"type":"log", "tickfont":{"size":10}},"barmode":"group","height":450, "legend":{"orientation":"h", "yanchor":"bottom", "y":1.02, "xanchor":"right", "x":1, "font":{"size":10}}, "titlefont":{"size":14}}}平面(未压缩 fp32)与两种乘积量化配置在 512 维向量存储的估计内存占用比较。对数刻度显示了 PQ 实现的显著内存节省,使得每个分片能够处理更大的数据集。虽然 PQ 显著减少内存,但它是一种有损压缩技术,可能影响召回率。压缩比(以及因此的内存/成本)与搜索准确性之间的权衡是一个主要调整参数。训练量化器需要数据的代表性子集,并且对于非常大的 $M$ 或 $k^*$,其本身可能计算密集。优化乘积量化 (OPQ) 预先转换向量,使其更好地符合 PQ 的假设,通常在相同压缩比下提高准确性。基于图的索引:分布式环境中的 HNSW分层可导航小世界 (HNSW) 图是流行的 ANN 算法,提供出色的召回-速度权衡。当分片 HNSW 索引时:每个分片在其向量子集上构建自己的 HNSW 图。查询针对每个分片的图运行,结果被合并。 HNSW 的构建参数(例如,$M$,efConstruction)和搜索时参数(例如,efSearch)需要根据每个分片进行调整。较高的 efSearch 通常会带来更好的召回率,但会增加延迟。分布式 HNSW 实现还必须在分片间高效管理图更新(插入/删除)。磁盘感知 ANN:当内存不足时对于超大数据集,即使压缩后的向量也无法完全放入集群的内存中时,基于磁盘的 ANN 索引变得必要。像 Faiss 这样的库支持 OnDiskInvertedLists,它将倒排列表(IVFADC 中的 posting lists)保存在磁盘上,通常是快速 SSD,而质心和可能一部分向量可以缓存在内存中。 使用基于磁盘的索引会因为 I/O 而显著增加查询延迟。然而,它能大幅降低运营成本。此类系统的设计通常涉及磁盘上细致的数据布局、优化的 I/O 模式和激进的缓存策略。分片仍然适用,每个分片管理自己的磁盘支持索引。规模化向量搜索的架构设计一个典型的规模化向量搜索子系统包含多个组件:客户端应用程序: 发出搜索查询。查询路由器/负载均衡器: 接收查询,进行认证,可能对它们进行丰富,并将它们路由到合适的向量搜索分片。它还汇总结果。向量索引分片: 多个实例,每个实例托管向量索引的一个分区及其副本。这些实例运行实际的 ANN 搜索算法。元数据存储: 通常,向量 ID 需要解析为实际的文档内容或其他元数据。此存储也必须具有可扩展性,并且可以共同定位或单独管理。索引构建/更新流水线: 一个独立的系统,负责生成嵌入,训练量化器(如果使用 PQ),构建索引结构,并将它们部署到分片。向量数据库或库的选择(例如,像 Milvus、Weaviate、Pinecone、Vespa 这样的专业解决方案,或像 Faiss、ScaNN 这样集成到自定义基础设施的库)将严重影响这些组件的实现和管理方式。许多托管向量数据库提供分片和复制作为内置功能,隐藏了一些底层复杂性。运营实际情况与权衡扩展向量搜索带来了运营复杂性。您必须考虑:成本: 更多节点意味着更高的基础设施成本。压缩技术和基于磁盘的索引可以减轻这一点,但会引入其他权衡。管理开销: 部署、监控和维护分布式系统比单个实例更复杂。自动化(IaC、CI/CD)必不可少。一致性与可用性: 对于索引更新,通常需要在确保所有副本即时一致和维持高可用性之间进行权衡。延迟与吞吐量与准确性与新鲜度: 这些通常是相互竞争的目标。例如,为了节省内存而进行更高压缩可能略微降低准确性。从副本提供过时数据可能会提高吞吐量但降低新鲜度。系统设计必须根据具体的 RAG 应用程序要求平衡这些方面。故障模式: 分布式系统有更多潜在故障点。监控、警报和自动化恢复机制是不可妥协的。成功扩展向量搜索是构建大规模 RAG 系统的重要基础。通过仔细应用分片、复制和选择合适的索引结构,可以在海量向量数据集上实现高吞吐、低延迟检索,为 RAG 流水线中后续生成阶段奠定基础。