ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

微服务延迟与资源成本的取舍

微服务延迟与资源成本的取舍 微服务延迟与资源成本的取舍接入检索与大模型之后微服务链路多了几个耗时和资源特征完全不同的阶段。网关与鉴权仍可能在毫秒级完成向量检索受网络和索引影响模型生成则会长时间占用连接与推理资源。把它们合成一个平均响应时间很难判断应该扩容、限流还是减少输入。延迟与成本的取舍要从请求路径和账单来源分别拆开。一次压测、一个 CPU 利用率或者模型供应商给出的 Token 单价都不足以支持架构结论。先定义用户真正等待的时间流式生成至少有三种时间请求进入到首个可见结果的时间、相邻输出之间的间隔以及任务完整结束的时间。用户可能在首段内容出现后就能开始阅读但连接与推理资源仍要等到生成完成才释放。因此首 Token 快不等于总成本低总耗时短也不代表输出过程流畅。RAG 链路可以继续拆成鉴权、查询改写、Embedding、向量检索、重排、上下文组装、模型排队、Prefill 和逐步生成。每段记录开始、结束、错误与取消状态并用同一个请求标识串联。短请求与长上下文任务分组统计避免一批简单任务把复杂任务的长尾藏起来。成本则按资源来源拆分外部 API 的输入与输出 Token、本地 GPU 占用时间、CPU 检索与重排、缓存和网络。最终可以看“完成一项有效任务”的资源而不是只看每次调用费用。无效重试、用户取消后仍继续的生成、校验失败的输出都消耗资源却没有产生完成结果。WebFlux 中先隔离阻塞调用使用 WebFlux 不会让同步客户端自动变成非阻塞。如果向量库 SDK 在 Netty EventLoop 上等待网络少量慢请求就可能阻塞其他连接。下面的写法把现有同步检索临时移到有边界的调度器再接流式模型客户端。RestController RequestMapping(/ai/chat) public class RagChatController { private final VectorStoreService vectorStore; private final LlmStreamClient llmClient; private final Scheduler retrievalScheduler; public RagChatController( VectorStoreService vectorStore, LlmStreamClient llmClient) { this.vectorStore vectorStore; this.llmClient llmClient; this.retrievalScheduler Schedulers.newBoundedElastic( 16, 200, rag-retrieval); } PostMapping(value /query, produces MediaType.TEXT_EVENT_STREAM_VALUE) public FluxString handle(RequestBody QueryRequest request) { return Mono.fromCallable(() - vectorStore.search(request.prompt())) .subscribeOn(retrievalScheduler) .timeout(Duration.ofSeconds(2)) .flatMapMany(documents - { String prompt PromptBuilder.build(documents, request.prompt()); return llmClient.streamOutput(prompt); }) .doOnCancel(() - llmClient.cancel(request.requestId())); } }线程数、队列和超时只是示例需要按同步客户端连接池与真实负载验证。timeout能停止 Reactor 链继续等待却不保证底层阻塞调用立即终止SDK 若提供真正的异步与取消接口应优先使用。调度器还要随应用关闭队列满时明确拒绝不能退回 EventLoop 执行。取消也要贯穿整个链路。浏览器断开 SSE 后网关、业务服务和模型客户端都应停止后续工作。只关闭最外层响应后台生成继续运行用户看不到结果账单和 GPU 占用却不会停止。检索缓存先解决一致性与隔离查询缓存可以减少重复 Embedding 和检索但键不能只有原始问题。租户、用户可见范围、索引版本、过滤条件、Embedding 模型和重排策略都会改变结果。缺少任一维度都可能返回过期内容甚至跨越访问边界。缓存内容还可能包含文档片段应按原数据权限保护并设置失效方式。知识库更新后是主动删除相关键还是通过索引版本自然切换要在设计中明确。命中缓存只省掉前置阶段不能用它解释模型生成的全部延迟。检索超时后“无上下文直接问模型”也不是通用降级。如果产品承诺基于知识库回答这样做可能生成没有依据的内容。更稳妥的选择是返回检索暂不可用或只展示明确标记的通用信息。降级是否允许由业务语义决定不能藏在exceptionally里静默发生。上下文裁剪要保留回答依据输入变长通常会增加 Prefill 工作与显存占用但具体关系受模型架构、推理实现、硬件和批处理影响不宜直接写成固定比例。应使用当前模型和引擎做基准测试同时记录输入长度、并发、批处理策略与输出上限。裁剪不能只按相似度阈值丢文档。先去除重复片段再按问题需要保留不同来源给系统提示、用户问题和检索内容分别设置预算。超过预算时记录哪些文档被舍弃回答端才能正确说明证据范围。Top K 也不是越小越省。K 太大增加重排与上下文成本太小可能漏掉必要证据。用带人工判断或明确答案的验证集比较召回、回答依据和延迟再确定不同任务的范围。不要拿单一硬件上的一次结果制作通用性能表。批处理和连接池都要防止隐藏排队动态批处理能提高 GPU 利用但会让请求等待凑批。交互式任务关注首 Token离线摘要则可以接受更长等待换取吞吐两者不应进入同一队列。至少按任务时限、输入规模和输出上限分组避免长任务阻塞短任务。网关连接池也应有边界。弹性、无明确上限的池会把压力推到下游过小的池又会在网关制造排队。先确定在哪一层排队并同时观察等待时间与连接占用。流式接口的超时要区分连接建立、长时间无数据和任务总时限简单把全局响应超时调大会让异常连接停留更久。模型路由根据可信策略不相信客户端标签不同任务使用不同模型可以控制资源但路由依据必须来自服务端已验证的用户权限和任务分类。客户端自带的X-User-Tier或意图头可以伪造不能直接决定高成本集群。路由策略还要验证能力兼容。轻量模型是否支持目标语言、结构化输出和所需上下文备用供应商是否遵守相同数据边界都应在上线前测试。切换模型会改变结果不能作为完全静默的网络重试。可以先把路由结果当作一份决策记录任务类别、模型版本、预算、原因和允许的降级路径。网关负责执行已经确定的目标不在过滤器中临时从用户文本猜意图。策略变化时使用同一验证集回放检查质量、延迟和成本而不是只看账单下降。用同一批任务寻找可接受区间取舍实验一次只调整一个主要条件例如并发、输入预算、Top K 或模型规格。使用相同任务集记录首 Token、完成时间、正确性、取消、错误和单位完成任务资源。分别报告冷缓存与热缓存明确样本范围和环境。最终结果通常不是一个“最优数字”而是几个服务等级交互请求限制排队与输出长度后台任务允许批处理证据不足的任务拒绝自动降级。每档写清适用任务、容量边界和用户提示。微服务调优的重点是让资源花在能完成的任务上。把阻塞调用移出事件循环、取消失效任务、限制隐藏队列再根据验证集调整上下文与模型延迟和成本才会成为可以解释的工程选择而不是两张互相矛盾的看板。
返回列表