资讯动态

多实例部署 AI 服务如何避免重复扣费:AI-Meeting 分布式 Single-flight 框架深度解析

发布时间:2026/10/16 21:09:14 来源:尧图企业网站定制
【免费下载链接】AI-Meeting基于 Spring Boot 3 Java 17 Spring AI MySQL MongoDB Redis SSE/WebSocket实现 AI 对话、智能体会话、AI 模拟面试、实时语音转写、长文本语音合成等核心功能。架构清晰、文档完整支持本地运行与 Docker 一键部署非常适合作为 Spring Boot AI 应用开发、智能体后端设计与简历展示项目。项目地址https://gitcode.com/gh_mirrors/ai/AI-Meeting点击查看免费下载AI-Meeting 是基于 Spring Boot 3 Java 17 Spring AI 的开源项目实现 AI 对话、智能体会话、AI 模拟面试、实时语音转写与长文本语音合成等核心功能。其中一套容易在面试中被追问、却在很多生产系统里真实存在的难题是服务扩容到多个实例后同一个用户的同一次请求会被多台机器各调一遍大模型Token 费用直接翻倍用户还会看到两份不一致的回答。AI-Meeting 用一套「本地 Redis 分布式」双层 Single-flight 框架把「同一次业务请求的重复 AI 调用」折叠成集群内的一次本文带你完整拆解它的实现思路。为什么多实例部署会让 AI 费用翻倍先看一个典型故障场景用户点击「提交回答」请求经负载均衡落到实例 AAI 评分需要 10~20 秒用户等不及刷新页面请求落到实例 B于是模型被调用了两次。单实例时代这个问题可以用「本地缓存 锁」解决因为所有请求都在同一个 JVM 里。但多实例部署后各实例的本地内存互不可见去重状态必须放到共享存储通常是 Redis中并且抢占动作必须原子化——否则两个实例会同时认为「我是第一个」重复调用照样发生。AI-Meeting 的面试链路提问、评分、追问、神态分析都是典型的「单次调用耗时数十秒、单次成本高」的 AI 场景正是这类框架的主战场。框架总览双层 Single-flight 架构核心入口是 InterviewAiInvoker.java它负责生成「请求指纹」single-flight key格式为stage|sessionId|questionNumber|answerHash评分、追问类调用stage|sessionId|businessKey文件、神态分析类调用key 由「阶段 会话 题号 答案内容的 SHA-256 摘要前 16 位」拼成。这意味着同一会话、同一题号、内容完全相同的答案无论落到哪个实例都会命中同一条 flight 记录从而天然实现跨实例去重。在这一层之上框架分两级工作层级实现作用范围核心类L1 本地ConcurrentHashMapCompletableFuture单实例内InterviewAiSingleFlightService.javaL2 分布式Redis Lua 脚本 状态机 心跳全部实例DistributedInterviewAiSingleFlightService.java第一层进程内 Single-flight毫秒级去重本地层实现非常精巧用flights.compute(key, ...)的原子操作保证「创建 flight 与复用 flight」不会同时发生避免瞬时并发下出现多个 leader首个请求leader真实调用 AI结果通过CompletableFuture.complete()广播给所有等待者后续请求waiter直接future.get()等待同一个结果超时默认 5s后主动剔除旧 flight防止永久挂起失败清理leader 异常时移除 key等待者也收到同样的异常保证语义一致。这一层拦截的是「同一实例内的重复点击、前端重试」等最高频的浪费且几乎零开销。第二层Redis 分布式协调跨实例去重跨实例协调的核心在 FlightCoordinatorRepository.java。整个抢占过程由一段Redis Lua 脚本原子执行这是避免「双主」的关键——任何「先 GET 再 SET」的两次网络往返都可能被两个实例穿插执行而 Lua 脚本在 Redis 中是单线程原子跑完的。脚本逻辑对应一个清晰的五路分支状态机OWNER_NEWkey 不存在 → 自增ownerToken写入PENDING元数据当前实例成为 ownerREPLAY_SUCCESS状态已是SUCCEEDED→ 直接回放已有结果一次模型都不调REPLAY_FAILURE上次失败且「不可重试」如参数校验错误→ 直接抛出相同错误避免反复重试确定性失败FOLLOWER_WAITowner 心跳仍在takeoverDetectMillis默认 10s内 → 当前实例降级为 follower等待结果OWNER_TAKEOVERowner 心跳超时或上次失败可重试 → 新实例生成新 token接管该请求。owner 拿到抢占权后还要执行markRunningCAS 校验 ownerId ownerToken 双身份确认无误才真正调用模型进一步杜绝「抢到又丢」的边界问题。心跳续租与故障接管长耗时调用的保活机制AI 调用动辄 20~60 秒但 Redis 元数据的runningTtlMillis只有 15 秒左右。如果 TTL 一过就被接管会出现「两个实例同时调用模型」的灾难。解决方案是心跳续租FlightHeartbeatManager.java 按 stage 策略默认 3s定时向 Redis 续租每次续租同样用 Lua 脚本 CAS 校验身份。这样设计带来一个优雅的故障语义实例正常 → 心跳持续续租TTL 永不到期实例宕机 → 心跳停发takeoverDetectMillis后其他实例自动接管故障恢复时间 ≈ 心跳间隔 × 3无需人工干预。结果回放与 L1 本地缓存命中后零模型调用owner 成功后做两件事见 DistributedInterviewAiSingleFlightService.java写入结果由 FlightResultSerializer.java 完成 gzip 压缩 Base64 编码 SHA-256 校验和控制 Redis 存储成本状态转SUCCEEDED并通过 FlightNotificationService.java 向 Redis Stream 发布终态事件让阻塞等待的 follower 立即被唤醒而非傻等轮询。follower 的等待采用「Stream 阻塞读 定时兜底轮询」双通道阻塞读最长 3s期间每 2s 轮询一次结果既低延迟又不怕通知丢失。此外每个实例还有 L1 本地回放缓存默认 1000 条、30s TTL同一实例的第二次命中连 Redis 都不用查。三种运行模式local / distributed / hybrid模式由 FlightMode.java 定义通过xunzhi-agent.ai-singleflight.mode切换模式行为适用场景local仅进程内去重单实例部署、联调distributed强制走 Redis 协调失败即报错对一致性要求高、宁可失败不可重复计费hybrid分布式优先Redis 异常时自动降级本地模式生产推荐AI-Meeting 默认hybrid模式体现了一个务实的取舍Redis 短暂抖动时宁可退回「实例内去重」保住可用性也不让整个面试功能不可用——去重是「省钱优化」不应成为功能可用性瓶颈。关键配置速查表全部配置集中在 application.yaml支持按 stage 差异化覆盖参数默认值含义modehybrid运行模式distributed-enabledtrue是否启用 Redis 协调follower-max-wait-millis20000follower 最长等待时间stream-block-timeout-millis3000Stream 阻塞读单次上限heartbeat-interval-millis3000心跳续租间隔按 stagerunning-ttl-millis15000运行态 TTL按 stagetakeover-detect-millis10000心跳多久未更新判定可接管result-ttl-millis600000成功结果回放窗口按 stagefailed-result-ttl-millis60000失败结果回放窗口compression-threshold-bytes4096超过该字节数结果才 gzip例如评分场景interview-evaluation结果保留 10 分钟、追问interview-followup保留 3 分钟、简历提取interview-extraction保留 30 分钟——TTL 就是「多久之内同样的请求允许免费回放」是防重复扣费最直接的旋钮。更多配置语义可参考项目内置说明 ai-singleflight.md 与 ai-guard.md。调优实践三个最容易被忽视的坑key 设计决定一切key 过粗如只含 sessionId会把不同题的调用误合并用户拿到错误答案key 过细如含时间戳则完全打不到。记住原则「什么算同一次业务调用」完全由 key 语义定义改 key 等于改去重边界。follower 等待要设上限等待过久用户会感知为卡顿。框架把follower-max-wait-millis控制在 20s 内超时后 follower 自行发起新调用此时大概率已命中结果回放。与限流熔断分层协作single-flight 只负责「折叠重复」超时/并发上限/熔断由同目录下的 AI Guard 体系负责见 AiCallGuardService.java两者叠加后同一请求在集群维度上「最多只产生一次真实的模型调用」重复扣费问题就此闭环。总结AI-Meeting 的分布式 Single-flight 框架给出了一套可直接借鉴的防重复扣费方案其设计精髓可浓缩为五点Lua 脚本原子抢占从根上消除「双 owner」ownerToken 递增 CAS 身份校验每次接管都是全新身份历史状态不会串扰心跳续租代替长锁TTL 短 高频续租宕机自动接管终态回放窗口TTL成功/失败都可在窗口内零成本回放hybrid 降级共享存储故障时优雅退化为实例内去重。这套机制不只适用于 AI 面试任何「高延迟、高单价、幂等可回放」的第三方调用大模型、支付、短信、OCR都可以套用同一模式。项目同时支持本地运行与 Docker 一键部署docker-compose.yml非常适合拿来动手阅读与二次实践。赞分享【免费下载链接】AI-Meeting基于 Spring Boot 3 Java 17 Spring AI MySQL MongoDB Redis SSE/WebSocket实现 AI 对话、智能体会话、AI 模拟面试、实时语音转写、长文本语音合成等核心功能。架构清晰、文档完整支持本地运行与 Docker 一键部署非常适合作为 Spring Boot AI 应用开发、智能体后端设计与简历展示项目。项目地址https://gitcode.com/gh_mirrors/ai/AI-Meeting点击查看免费下载相关推荐Redis Lua Single-Flight与Fencing TokenFinSight AI如何杜绝重复AI分析和缓存击穿Redis Lua Single Flight与Fencing TokenFinSight AI如何杜绝重复AI分析和缓存击穿 FinSight AI 是一款SmartJavaAI微服务架构分布式AI能力部署SmartJavaAI微服务架构分布式AI能力部署 引言AI能力部署的挑战与机遇 在当今数字化转型浪潮中人工智能AI能力已成为企业核心竞争力。然而传人工智能计算机视觉语音NLPOCR本地部署MCSManager 分布式架构深度解析如何实现多服务器统一管理MCSManager 分布式架构深度解析如何实现多服务器统一管理 MCSManager 是一款功能强大的 开源 Minecraft 服务器管理面板 专为分布后端前端运维创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑