尽管优化单个组件的延迟是重要的一步,但您的 RAG 系统处理大量并发请求的能力,特别是在高峰负载期间,对生产可用性非常重要。吞吐量,通常以每秒查询数 (QPS) 来衡量,量化了这种容量。一个对单个用户来说速度快,但在许多并发用户压力下崩溃的系统,无法用于生产。设计和实施 RAG 系统以有效地扩展其吞吐量来满足波动需求的策略,将在此详细说明。扩展吞吐量通常涉及横向扩展(增加更多机器或实例)和纵向扩展(增加现有机器的资源)的组合,以及智能工作负载管理。目标是确保随着传入请求数量的增加,系统能够按比例增加其处理容量,而不会导致响应时间明显下降或错误率增加。了解吞吐量瓶颈在扩展之前,识别您的 RAG 管道的哪些部分限制了整体吞吐量很重要。虽然延迟分析侧重于每个步骤所花费的时间,但吞吐量分析着眼于每个组件可以并发处理或单位时间内处理多少请求。常见瓶颈包含:LLM 推理服务:大型语言模型是计算密集型的。如果您使用第三方 API,您可能会遇到速率限制。如果是自托管,您的模型服务基础设施可以处理的并发推理数量将是主要瓶颈。嵌入模型推理:与 LLM 类似,为查询和文档生成嵌入需要大量计算,通常在 GPU 上进行。您的嵌入服务的容量可以限制可以同时处理的新文档或嵌入的查询数量。向量数据库:向量数据库需要处理高频相似度搜索查询。其索引策略、硬件和读取扩展能力将直接影响吞吐量。应用逻辑层:管理 RAG 流程(接收请求、调用各种服务、组合结果)的协调代码,如果未设计为支持并发,则可能成为瓶颈,例如由于同步阻塞调用或效率低下的资源管理。数据摄取管道:虽然不直接属于用户查询路径,但您的数据摄取和嵌入管道的吞吐量可以限制新信息在 RAG 系统中变得可用的速度。性能分析工具、负载测试框架和全面监控对于在模拟峰值负载条件下找出这些瓶颈非常重要。横向扩展策略横向扩展,或称向外扩展,涉及将负载分布到您的应用程序组件的多个实例。这通常是提高无状态或易于分区的服务吞吐量最具成本效益和弹性的方式。复制无状态组件您的主要 RAG 应用程序服务器、嵌入模型服务器和重排模型服务器等组件通常是无状态的。这意味着每个请求可以由任何实例独立处理。负载均衡器:负载均衡器放置在这些复制实例的前面。它使用各种算法(例如轮询、最少连接)在可用实例之间分配传入请求。这可以防止任何单个实例过载,并允许系统并行处理更多请求。服务发现:随着实例的添加或移除(特别是在像 Kubernetes 这样的动态环境中),服务发现机制可以确保负载均衡器和其他服务能够找到活跃实例。下图呈现了横向扩展的 RAG 应用程序层。digraph G { rankdir=LR; node [shape=component, style=filled, fillcolor="#e9ecef"]; edge [color="#495057"]; subgraph cluster_user { label="用户请求"; style=filled; color="#f8f9fa"; User [label="用户\n请求", shape=rect, fillcolor="#a5d8ff"]; } LB [label="负载均衡器", shape=cds, fillcolor="#96f2d7"]; subgraph cluster_app_servers { label="RAG 应用服务器 (副本)"; style=filled; color="#f8f9fa"; App1 [label="应用服务器 1", fillcolor="#ced4da"]; App2 [label="应用服务器 2", fillcolor="#ced4da"]; AppN [label="应用服务器 N", fillcolor="#ced4da"]; } subgraph cluster_downstream { label="下游服务"; style=filled; color="#f8f9fa"; EmbService [label="嵌入\n服务", fillcolor="#ffc9c9"]; VecDB [label="向量数据库", shape=cylinder, fillcolor="#eebefa"]; LLMService [label="LLM 服务", fillcolor="#bac8ff"]; } User -> LB; LB -> App1; LB -> App2; LB -> AppN; App1 -> EmbService; App1 -> VecDB; App1 -> LLMService; App2 -> EmbService; App2 -> VecDB; App2 -> LLMService; AppN -> EmbService; AppN -> VecDB; AppN -> LLMService; {rank=same; App1 App2 AppN} }负载均衡器将传入的用户请求分配到 RAG 应用程序服务器的多个复制实例。每个应用程序服务器实例然后与共享或独立扩展的下游服务(如嵌入模型、向量数据库和 LLM)交互。扩展向量数据库向量数据库通常有其自身的扩展查询吞吐量机制:读取副本:许多向量数据库支持读取副本。这些是主数据库(或其分片)的副本,可以处理查询流量,分散读取负载。分片(分区):对于很大的索引或非常高的查询量,向量索引本身可以在多个节点上分片或分区。每个分片保存数据的子集,查询可以路由到相关分片或广播到所有分片并聚合结果。这允许在数据库级别进行并行查询处理。扩展 LLM 访问如果 LLM 推理是瓶颈:第三方 API:如果您面临每个密钥的速率限制,请将请求分配到多个 API 密钥。一些提供商还提供具有更高速率限制的更高级别计划。考虑使用可以处理请求排队和分配的托管网关。自托管 LLM:在负载均衡器后面部署您的 LLM 服务端点的多个实例。如果通过 vLLM、TGI 或 Triton 推理服务器等框架提供开源模型,这尤其相关。确保您的 GPU 资源与实例数量同步扩展。纵向扩展策略纵向扩展,或称向上扩展,涉及增加托管您的 RAG 组件的单个机器的资源(CPU、RAM、GPU 显存、网络带宽)。何时使用:纵向扩展在最初实施时可能比横向扩展更简单,特别是对于有状态组件或当进程间通信开销是一个问题时。对于像 LLM 或嵌入推理等 GPU 密集型任务,使用更强大的 GPU(例如从 A10G 升级到 A100 或 H100)可以显著提高单个推理服务器的吞吐量。限制:成本:高端硬件可能很昂贵。上限:单个机器可以向上扩展的物理限制。单点故障:仅依赖一台强大的机器会增加该机器发生故障的风险(除非与高可用性设置结合)。通常,混合方法最佳:纵向扩展到某个最佳实例大小,然后使用这些优化实例进行横向扩展。动态负载的自动扩缩容峰值负载通常是瞬时的。始终为绝对最大预期负载预配基础设施通常成本过高。自动扩缩容根据实时需求动态调整 RAG 组件的活跃实例数量。指标驱动的调整:自动扩缩容系统监控 CPU 利用率、内存使用量、请求队列长度等指标,或每个实例的每秒查询数 (QPS) 等自定义指标。扩缩容策略:您可以定义触发扩缩容操作的策略。例如:如果应用程序服务器的平均 CPU 利用率在 5 分钟内超过 70%,则添加 2 个新实例。如果 LLM 推理请求队列长度超过 100,则部署一个额外的 LLM 服务副本。如果每个实例的 QPS 降至某个阈值以下,则缩减实例数量以节省成本。平台:云提供商(AWS Auto Scaling Groups、Azure VM Scale Sets、Google Managed Instance Groups)和容器编排平台(如 Kubernetes 的 Horizontal Pod Autoscaler - HPA)提供自动扩缩容功能。下图呈现了活跃实例数量如何根据波动的请求量进行扩缩容。{"data": [{"name": "传入请求 (QPS)", "x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "y": [100, 120, 300, 550, 700, 450, 300, 250, 600, 350, 150], "type": "scatter", "mode": "lines+markers", "line": {"color": "#228be6"}}, {"name": "活跃实例", "x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "y": [2, 2, 3, 5, 7, 5, 3, 3, 6, 4, 2], "type": "scatter", "mode": "lines+markers", "yaxis": "y2", "line": {"color": "#40c057", "shape": "hv"}, "marker": {"symbol": "square"}}], "layout": {"title": "RAG 实例自动扩缩容与请求负载对比", "xaxis": {"title": "时间 (小时)"}, "yaxis": {"title": "传入请求 (QPS)", "titlefont": {"color": "#228be6"}, "tickfont": {"color": "#228be6"}}, "yaxis2": {"title": "活跃实例数量", "titlefont": {"color": "#40c057"}, "tickfont": {"color": "#40c057"}, "overlaying": "y", "side": "right", "range": [0, 8]}, "legend": {"x": 0.5, "y": 1.15, "xanchor": "center", "orientation": "h"}, "autosize": true, "paper_bgcolor": "#f8f9fa", "plot_bgcolor": "#e9ecef"}}随着传入请求(蓝线)随时间波动,自动扩缩容系统会根据需求向上或向下调整活跃的 RAG 处理实例数量(绿线),从而优化性能和成本。自动扩缩容对于处理不可预测的流量高峰以及确保您的 RAG 系统在不过度分配资源的情况下保持响应性非常重要。请求批处理以提升吞吐量尽管通常在减少单个调用延迟(通过一次处理多个项目)的背景下讨论,但请求批处理在提高整体系统吞吐量方面也发挥重要作用,特别是对于 RAG 系统中常见的 GPU 密集型操作,如嵌入生成和 LLM 推理。工作原理:不再逐个将单个项目(例如,用于嵌入的文档、用于生成的提示)发送到模型服务器,而是收集一批项目并一起发送。GPU 是高度并行的处理器,在批量处理数据时,可以实现更好的利用率和更高的吞吐量。权衡:延迟增加(批次中每项):批次中的第一项在处理开始之前必须等待批次被填满(或发生超时)。吞吐量增加(整体):系统可以在单位时间内处理更多项目。动态批处理:精密的系统可以实施动态批处理,其中批次大小和等待时间(超时)根据当前请求负载进行调整。在低负载下,较小的批次或较短的超时时间可最小化延迟。在高负载下,较大的批次可最大化吞吐量。像 NVIDIA Triton Inference Server 这样的框架为模型服务提供了开箱即用的高级动态批处理功能。并发管理和异步操作在应用程序层中有效管理并发对于吞吐量很重要。线程/进程池:在您的应用程序服务器中配置线程或进程池的适当大小,以处理并发请求,而不会耗尽资源或引入过多的上下文切换开销。异步编程:如在延迟上下文中讨论的,使用异步 I/O 操作(例如 async/await 模式)允许单个线程通过不阻塞 I/O 密集型操作(如对向量数据库或 LLM API 的网络调用)来处理许多并发请求。这直接转换为应用程序服务器实例的更高吞吐量。连接池:建立和管理到下游服务(如向量数据库和 LLM API)的连接池。重用现有连接可以避免为每个请求建立新连接的开销,这在高负载下可能是一个明显瓶颈。监控吞吐量指标为了有效扩展和管理吞吐量,您需要持续监控相关指标:每秒查询数 (QPS):跟踪系统的整体 QPS 以及单个组件(应用程序服务器、嵌入服务、LLM 端点、向量数据库)的 QPS。组件利用率:每个组件的 CPU、GPU、内存和网络利用率。高利用率通常表明存在瓶颈。队列长度:监控 LLM 推理或批处理作业等服务的请求队列长度。不断增长的队列表明下游服务无法跟上。错误率:在负载下跟踪错误率(例如 HTTP 5xx 错误)。错误增加通常表明组件不堪重负。饱和度:衡量服务“满负荷”的程度,表明它离其性能极限有多近。这些指标不仅对于识别瓶颈很重要,而且还作为自动扩缩容策略和容量规划的输入。针对吞吐量进行设计需要积极主动的方法,预测负载变化并在您的 RAG 系统架构中构建弹性。通过结合横向和纵向扩展、实施自动扩缩容、优化批处理和并发以及勤奋监控性能,您可以构建能够高效可靠地处理生产级别流量的 RAG 系统。