首页 / 资讯中心 / 文章详情

AI应用底座实战:微服务架构与JDK 21适配指南

AI应用底座实战:微服务架构与JDK 21适配指南 ★ FEATURED ARTICLE
1. 从一次深夜救火说起为什么“AI 应用底座”不是伪命题去年冬天一个做智能客服的朋友半夜给我打电话说他们的 AI 问答服务又挂了。不是模型挂了是模型前面那层业务系统挂了——用户会话状态丢了知识库检索接口超时限流规则没生效导致一个爬虫把整个问答集群打满。他原话是“我们花了三个月调模型结果死在了一堆 CRUD 接口上。”这个场景我太熟了。过去两年几乎每一家说自己“在做 AI 应用”的团队都会经历这个阶段模型能力很强Demo 很惊艳但一旦要接入真实业务、真实用户、真实并发整个系统就开始露怯。问题从来不在模型本身而在于模型下面那层“地基”没人认真搭。QuickBlue 就是冲着这层地基来的。你可以把它理解成一个AI 应用底座——它不训练模型也不做具体的业务功能它解决的是“当你要把 AI 能力塞进一个真实的企业系统时那些绕不开的脏活累活”。比如统一鉴权、会话管理、多模型路由、限流熔断、知识库检索编排、日志追踪、灰度发布。这些东西单拎出来都不难但要把它们组合成一个稳定、可扩展、能扛住生产流量的底座工作量远超大多数团队的预期。这篇文章适合三类人看第一类是在企业里负责 AI 落地、被各种“模型接进去就完事”的说法坑过的技术负责人第二类是想了解 AI 应用后端架构到底长什么样的后端工程师第三类是做微服务架构、正在考虑怎么把 AI 能力作为一类标准服务纳入现有体系的架构师。我会从 QuickBlue 的设计思路讲起拆到微服务拆分、Spring Cloud 组件选型、JDK 21 的适配细节再给出一套可参考的实操路径和踩坑记录。不吹概念只讲我实际验证过的东西。2. QuickBlue 到底解决了什么问题AI 应用底座的定位拆解2.1 先搞清楚“底座”和“平台”的区别很多人一听到“底座”就联想到“平台”觉得又是一个大而全的东西。这两个词在企业软件语境里差别很大。平台通常面向最终用户提供可视化界面、开箱即用的功能比如一个低代码平台、一个数据分析平台。底座面向的是开发者和系统本身它不直接产生业务价值但没有它上面的业务就搭不稳。打个比方平台像是商场里已经装修好的店铺你拎包入驻就能卖货底座像是商场的地基、水电、消防、承重结构。QuickBlue 属于后者。它提供的是一组标准化的基础能力让 AI 应用开发者不用每次都从零实现鉴权、限流、会话、路由这些东西。这个定位决定了 QuickBlue 的几个特征第一它是无业务侵入的不会规定你的 AI 应用必须长什么样第二它是可组合的你需要哪个能力就接哪个第三它是面向生产的所有设计都以稳定性和可观测性为优先而不是 Demo 跑通就行。2.2 AI 应用相比传统应用多了哪些“底座级”需求传统微服务该有的东西AI 应用一样都不能少服务注册发现、配置中心、网关、熔断限流、链路追踪。但 AI 应用额外多了几类需求这些是普通业务系统不会重点考虑的。第一类是模型调用的不确定性。传统接口的响应时间基本可控但大模型推理的延迟波动极大同一个请求可能 800ms 返回也可能 8 秒才返回。这就要求底座在超时控制、重试策略、降级方案上做特殊处理——不能简单套用传统的固定超时。第二类是会话与上下文管理。AI 对话是有状态的多轮对话需要维护上下文窗口。这个状态存在哪里、怎么过期、怎么在多实例之间共享都是底座要解决的问题。用本地内存存多实例部署就废了。用 Redis 存那序列化格式、过期策略、并发读写又得设计。第三类是多模型路由与成本控制。企业往往同时接入了多个模型供应商不同模型的成本、能力、可用性都不一样。底座需要提供统一的路由层支持按业务场景、按成本预算、按可用性动态选择模型还要能统计每个业务线消耗了多少 token。第四类是知识库检索编排。RAG 架构里检索环节涉及向量库查询、关键词召回、重排序等多个步骤这些步骤的编排、超时控制、结果合并都是底座层面的工作。QuickBlue 的价值就在于它把这四类需求都抽象成了标准组件你不用每个项目重新造一遍轮子。2.3 为什么企业自研底座往往失败我见过不少团队尝试自研 AI 应用底座最后要么半途而废要么做出来没人用。原因通常有三个。一是低估了非功能性需求的复杂度。写一个能跑的鉴权拦截器可能只要半天但要写出能扛住每秒几千次并发、支持动态规则更新、有完整审计日志的鉴权组件工作量是前者的几十倍。很多团队按“能跑就行”的标准做底座结果上线后到处是坑。二是没有考虑多团队协作。底座是给多个业务团队用的接口设计、版本管理、向后兼容、文档维护这些“软”工作往往被忽略。等三个业务团队都接进来之后改一个接口就要协调三方底座反而成了瓶颈。三是缺乏生产验证。底座的问题往往在高并发、异常场景下才暴露。自研底座如果没有经过真实流量打磨很容易在关键时刻掉链子。QuickBlue 这类经过多个项目验证的底座价值就在于它已经踩过大部分坑。3. 微服务拆分QuickBlue 的骨架是怎么搭的3.1 拆分原则按“能力边界”而不是“技术分层”很多团队做微服务拆分时习惯按技术分层拆网关一层、业务一层、数据一层。这种拆法在 AI 应用场景下会出问题因为 AI 应用的很多能力是横跨多层的。比如“模型调用”这个能力它既涉及网络通信又涉及业务路由还涉及数据统计硬按技术层拆会导致一个完整能力被切碎在多个服务里。QuickBlue 的拆分思路是按能力边界拆。我把它核心的服务划分整理成下面这张表你可以对照自己的项目看看是否合理。服务名称核心职责拆分理由接入网关服务统一入口、鉴权、限流、协议转换所有流量必经之路独立部署便于统一管控会话管理服务会话创建、上下文存储、过期清理有状态服务需要独立扩缩容和存储设计模型路由服务多模型选择、负载均衡、成本统计路由策略变化频繁独立部署便于快速迭代知识检索服务向量检索、关键词召回、结果重排检索逻辑复杂且与模型调用解耦编排引擎服务多步骤流程编排、超时控制、降级编排逻辑是 AI 应用的核心差异点可观测服务日志聚合、指标采集、链路追踪横切关注点独立部署避免侵入业务这个拆法的好处是每个服务的边界清晰团队可以并行开发。比如模型路由服务由算法工程团队维护会话管理服务由后端团队维护互不干扰。3.2 服务间通信同步还是异步这是个问题AI 应用的通信模式比传统业务复杂。传统业务大多是“请求-响应”同步模式但 AI 应用里一次用户请求可能触发多个异步任务模型推理、知识检索、日志上报、计费统计。如果全部用同步调用一个环节慢就拖垮整条链路。QuickBlue 的做法是核心链路同步、辅助链路异步。用户请求进来后鉴权、会话读取、模型路由这几个环节是同步的因为后续步骤依赖它们的结果。而日志上报、计费统计、质量评估这些环节走异步消息不阻塞主流程。具体实现上同步通信用 Spring Cloud OpenFeign异步通信用消息队列。这里有个细节值得说Feign 的默认超时时间在 AI 场景下往往不够用因为模型推理可能耗时较长。我的经验是把连接超时设为 2 秒读取超时根据业务场景单独配置对话类接口设 30 秒批处理类接口设 120 秒并且一定要配合熔断器使用避免线程池被慢请求占满。3.3 配置管理为什么 AI 应用的配置比普通应用更“活”AI 应用的配置变化频率远高于传统应用。模型版本会更新、路由权重会调整、限流阈值会随业务波动、提示词模板会迭代。如果每次改配置都要重启服务运维成本会很高。QuickBlue 用配置中心统一管理这些动态配置并且做了配置分级全局配置如模型供应商列表、服务级配置如本服务的限流阈值、实例级配置如本实例的灰度标记。分级的好处是改全局配置影响所有服务改服务级配置只影响特定服务避免误操作扩大影响面。注意动态配置一定要有回滚机制和变更审计。我踩过的坑是某次调整路由权重时手滑多打了一个零导致所有流量打到最贵的模型上半小时烧掉了一笔不小的费用。后来我们强制要求所有配置变更必须走审批流并且支持一键回滚。4. Spring Cloud 组件选型哪些是刚需哪些可以省4.1 注册中心与配置中心Nacos 还是 ConsulSpring Cloud 生态里注册中心和配置中心的可选项不少。QuickBlue 选的是 Nacos理由有三个一是它同时提供注册和配置两个功能减少组件数量二是它对 Spring Cloud Alibaba 生态支持成熟文档和社区案例多三是它的控制台对运维友好排查问题方便。Consul 也是不错的选择尤其在多数据中心场景下更有优势。但如果你的部署环境相对单一Nacos 的性价比更高。这里的关键不是选哪个而是不要同时用两套注册中心。我见过有的项目历史遗留一部分服务注册在 Eureka一部分在 Nacos结果服务发现经常出问题排查起来极其痛苦。4.2 网关选型Spring Cloud Gateway 的实战配置网关是 AI 应用底座的咽喉。QuickBlue 用的是 Spring Cloud Gateway核心原因是它基于响应式编程模型在高并发场景下资源利用率比传统的 Servlet 网关更好。网关层我重点配置了三块路由规则、过滤器链、限流。路由规则按业务线划分比如/api/chat/**走对话服务/api/knowledge/**走知识检索服务。过滤器链里鉴权过滤器排在最前面然后是日志过滤器、限流过滤器。限流用的是 Redis 加令牌桶算法因为网关是多实例部署必须用分布式限流。spring: cloud: gateway: routes: - id: chat-service uri: lb://chat-service predicates: - Path/api/chat/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 100 redis-rate-limiter.burstCapacity: 200 key-resolver: #{userKeyResolver}上面这段配置的意思是对话服务每秒补充 100 个令牌桶容量 200按用户维度限流。replenishRate和burstCapacity这两个参数需要根据实际压测结果调整不能拍脑袋定。我的经验是先设一个保守值上线后观察 Redis 里的令牌消耗曲线再逐步调优。4.3 熔断限流Sentinel 的规则持久化是个坑Sentinel 是 Spring Cloud Alibaba 体系里做熔断限流的标配。但很多人用 Sentinel 时忽略了一个问题默认规则存在内存里服务重启就丢了。生产环境必须做规则持久化。QuickBlue 的做法是把 Sentinel 规则持久化到 Nacos服务启动时从 Nacos 拉取规则规则变更时通过 Nacos 推送。这样规则不会因为重启丢失也支持动态调整。配置上需要引入sentinel-datasource-nacos依赖然后在配置文件里指定 Nacos 的数据源。spring: cloud: sentinel: datasource: flow: nacos: server-addr: ${NACOS_ADDR} dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow提示Sentinel 的流控规则和熔断规则要分开配置。流控是限制入口流量熔断是当依赖服务异常时快速失败。两者作用点不同不要混在一起调。4.4 链路追踪AI 应用的追踪比普通应用更难普通微服务的链路追踪相对简单一个请求经过几个服务串起来就行。但 AI 应用的链路里多了模型调用这个“黑盒”模型内部的耗时、token 消耗、返回质量都需要额外埋点。QuickBlue 在标准链路追踪的基础上增加了模型调用维度的埋点每次模型调用记录模型名称、输入 token 数、输出 token 数、首 token 延迟、总延迟。这些数据汇总后可以分析出哪个模型在哪个场景下性价比最高。这个能力在成本优化阶段非常有用我靠它发现某个业务线用了一个贵三倍的模型但效果提升不到 5%换掉之后成本直接降了一半。5. JDK 21 适配新特性用得好是红利用不好是坑5.1 为什么 AI 应用底座值得升级到 JDK 21JDK 21 是 LTS 版本对 AI 应用底座来说有几个实打实的收益。虚拟线程是最值得关注的一个。AI 应用里大量操作是 IO 密集型的——调模型、查向量库、读写 Redis这些操作在传统线程模型下会阻塞平台线程。虚拟线程让每个请求可以用一个虚拟线程处理阻塞时自动让出底层载体线程吞吐量提升明显。我做过一个对比测试同样的模型调用接口用传统线程池200 并发时响应时间开始明显上升换成虚拟线程后500 并发下响应时间仍然平稳。当然虚拟线程不是银弹它解决的是 IO 阻塞问题CPU 密集型任务该用线程池还是用线程池。另一个收益是记录模式Record Patterns和模式匹配让处理复杂的请求响应结构时代码更简洁。AI 应用的请求体往往嵌套很深用模式匹配解构比一层层 get 清爽很多。5.2 虚拟线程在网关和业务服务里的正确用法虚拟线程用起来很简单但用对不容易。最常见的错误是把虚拟线程和线程池混用。虚拟线程的设计初衷是“一个任务一个虚拟线程”不需要池化。如果你把虚拟线程放进线程池就失去了它的意义。在 Spring Boot 3.2 及以上版本里开启虚拟线程只需要一个配置spring: threads: virtual: enabled: true开启后Tomcat 的请求处理会自动使用虚拟线程。但要注意如果你在代码里手动创建了线程池那些任务还是跑在平台线程上。我的做法是把业务代码里的Executors.newFixedThreadPool逐步替换成Executors.newVirtualThreadPerTaskExecutor让所有 IO 密集型任务都享受虚拟线程的红利。注意虚拟线程下ThreadLocal的使用要格外小心。虚拟线程数量可能非常多如果每个线程都存一份 ThreadLocal 数据内存占用会飙升。AI 应用里常见的用户上下文、追踪 ID建议改用ScopedValueJDK 21 预览特性或者显式传参。5.3 升级 JDK 21 时容易忽略的兼容性问题从 JDK 8 或 11 升到 21大部分代码不用改但有几个地方容易出问题。一是反射相关的库一些老版本的序列化库、代理库在 JDK 21 下会报模块访问错误需要升级到新版本。二是GC 行为变化JDK 21 默认的 G1 在参数调优上和旧版本有差异升级后要重新观察 GC 日志必要时调整MaxGCPauseMillis。三是依赖的 Spring Cloud 版本JDK 21 需要 Spring Boot 3.2 及以上Spring Cloud 2023.0 及以上版本不匹配会出现各种奇怪的启动错误。我的建议是升级前先在测试环境跑一轮完整的回归测试重点观察启动日志里的警告信息和运行时的 GC 表现。不要直接在生产环境升级哪怕你觉得“只是换个 JDK 而已”。6. 实操路径从零搭一个最小可用的 AI 应用底座6.1 环境准备与依赖版本锁定搭底座最怕版本冲突。我建议在动手之前先把版本矩阵定下来并且写进父 POM 的dependencyManagement里所有子模块统一继承。下面是我验证过的一套组合组件版本说明JDK21LTS支持虚拟线程Spring Boot3.2.x支持虚拟线程和 JDK 21Spring Cloud2023.0.x与 Spring Boot 3.2 匹配Spring Cloud Alibaba2023.0.x提供 Nacos、SentinelNacos2.3.x注册与配置中心Redis7.x会话存储与分布式限流Sentinel1.8.x熔断限流版本锁定之后创建一个父工程把公共依赖、插件配置、编码规范都放在父 POM 里。子模块只声明自己需要的依赖不写版本号。这样做的好处是将来升级某个组件时只改父 POM 一处。6.2 网关服务的核心配置与启动验证网关是第一个要跑起来的服务。创建gateway-service模块引入spring-cloud-starter-gateway和spring-cloud-starter-alibaba-nacos-discovery。启动类上加EnableDiscoveryClient。配置文件里重点配三块Nacos 地址、路由规则、跨域。跨域这块 AI 应用经常遇到因为前端可能部署在不同域名下。Spring Cloud Gateway 的跨域配置和传统 Spring MVC 不一样要用CorsWebFilter或者配置文件里的globalcors。启动后先验证网关能否从 Nacos 拉到服务列表再验证路由规则是否生效。我的习惯是用curl直接打网关端口看请求有没有被正确转发。这一步看起来简单但很多问题比如路由不生效、过滤器顺序错乱都是在这一步暴露的。6.3 会话管理服务的存储设计会话管理服务的核心是存储设计。我选的是 Redis 加本地缓存的二级结构热点会话放本地缓存减少 Redis 访问全量会话放 Redis保证多实例共享。Redis 的 key 设计要包含租户 ID 和会话 ID比如session:{tenantId}:{sessionId}。value 用 Hash 结构存字段包括上下文消息列表、最后活跃时间、模型偏好等。过期时间设 30 分钟每次读写时刷新。这里有个细节上下文消息列表不能无限增长要设一个上限超过后按时间淘汰最老的消息。我设的上限是 20 轮对话超过后把最早的两轮压缩成摘要。public void appendMessage(String tenantId, String sessionId, Message message) { String key session: tenantId : sessionId; redisTemplate.opsForHash().put(key, lastActive, System.currentTimeMillis()); redisTemplate.opsForList().rightPush(key :messages, message); Long size redisTemplate.opsForList().size(key :messages); if (size ! null size MAX_MESSAGES) { redisTemplate.opsForList().trim(key :messages, size - MAX_MESSAGES, -1); } redisTemplate.expire(key, Duration.ofMinutes(30)); }上面这段代码是简化版实际生产里还要考虑并发写入的原子性建议用 Lua 脚本把多个操作打包。6.4 模型路由服务的策略实现模型路由服务是 QuickBlue 里最能体现“AI 应用底座”特色的部分。它的核心是一个策略链先按业务场景过滤可用模型再按成本预算排序最后按当前负载做负载均衡。策略链的每个环节都可以配置。比如某个业务场景要求“必须用支持长上下文的模型”那就在过滤环节加上上下文长度条件。某个业务线有成本上限那就在排序环节按单价升序排。负载均衡环节我用了加权轮询权重根据模型的实时健康度动态调整——连续失败的模型权重降低恢复后逐步回升。public ModelRoute selectRoute(RouteContext context) { ListModelCandidate candidates filterByScene(context.getScene()); candidates filterByCapability(candidates, context.getRequiredCapabilities()); candidates sortByCost(candidates, context.getCostBudget()); return loadBalance(candidates); }这个策略链的好处是每个环节职责单一新增策略时不用改其他环节。比如后来要加一个“按地域就近选择模型”的策略只需要在过滤环节加一个条件不影响排序和负载均衡。7. 常见问题与排查技巧实录7.1 服务注册上了但调不通先查这三处这是最高频的问题。服务在 Nacos 控制台能看到但 Feign 调用报“无可用实例”。排查顺序是第一看调用方和服务提供方是否在同一个命名空间和分组Nacos 默认按命名空间隔离跨命名空间发现不了第二看服务提供方的健康检查是否通过有时候服务注册了但健康检查失败Nacos 会把它标记为不健康第三看网络是否互通尤其是容器化部署时Pod 之间的网络策略可能挡住了端口。我踩过最坑的一次是服务提供方注册的是容器内网 IP但调用方在另一个网络里根本访问不到。后来统一改成注册宿主机 IP 才解决。这个问题的根因是 Nacos 客户端默认取的是网卡 IP多网卡环境下可能取错需要在配置里显式指定。7.2 限流规则不生效的几种典型原因Sentinel 限流不生效常见原因有四个。一是规则没持久化服务重启后规则丢了二是资源名写错了Sentinel 是按资源名匹配的资源名对不上规则就不生效三是规则类型选错了流控规则和熔断规则的作用点不同四是 Sentinel 的切面没生效比如用了异步调用Sentinel 的默认切面拦不住。排查时我习惯先看 Sentinel 控制台的“簇点链路”确认资源有没有被识别到。如果资源列表是空的说明切面没生效检查依赖和配置。如果资源有但规则不生效检查规则配置的资源名和实际资源名是否一致。7.3 虚拟线程下 ThreadLocal 丢失的排查开启虚拟线程后如果发现用户上下文丢失大概率是 ThreadLocal 的问题。虚拟线程在阻塞时会让出载体线程如果代码里依赖 ThreadLocal 传递上下文切换载体线程后上下文就丢了。解决办法有两个一是改用ScopedValue它是 JDK 21 引入的不可变上下文传递机制天然支持虚拟线程二是显式传参把上下文作为方法参数传递不依赖 ThreadLocal。我倾向于第二种虽然代码稍微啰嗦但最不容易出问题。7.4 常见问题速查表现象可能原因排查方向服务注册了但调不通命名空间/分组不一致、健康检查失败、网络不通检查 Nacos 配置和网络策略限流规则不生效规则未持久化、资源名不匹配、切面未生效查看簇点链路和规则配置虚拟线程下上下文丢失ThreadLocal 跨载体线程失效改用 ScopedValue 或显式传参模型调用超时频繁超时设置过短、模型服务过载调整超时参数、增加熔断降级配置变更后服务异常配置格式错误、缺少回滚机制检查配置内容、执行回滚8. 我在实际项目里踩过的几个坑第一个坑是过度拆分。一开始我把模型路由拆成了“路由决策”和“路由执行”两个服务结果发现两者耦合太紧每次改路由策略都要同时改两个服务反而降低了效率。后来合并成一个服务边界反而更清晰。微服务拆分不是越细越好拆到“一个服务对应一个完整能力”就够了。第二个坑是忽略冷启动。AI 应用底座的服务启动时要连接 Nacos、Redis、消息队列还要预热模型路由的缓存。如果没做预热服务刚启动那几分钟响应特别慢。后来我在启动类里加了预热逻辑服务就绪前先把常用配置和路由规则加载到本地缓存。第三个坑是日志量失控。AI 应用的日志比普通应用多得多每次模型调用都要记录输入输出。如果不做采样和分级日志文件几天就撑爆磁盘。我的做法是错误日志全量记录正常调用按 1% 采样调试日志只在特定条件下开启。这样既保留了排查问题的能力又控制了存储成本。第四个坑是成本监控缺失。前面提过我因为配置错误烧了一笔钱。后来我在模型路由服务里加了实时成本统计每个业务线、每个模型的 token 消耗和费用都实时上报超过阈值就告警。这个功能后来成了我们优化成本的主要依据。9. 这套底座后续还能怎么扩展QuickBlue 作为 AI 应用底座本身是一个持续演进的东西。我目前在做的一个扩展方向是多模态能力的统一接入。现在底座主要处理文本模型但图片生成、语音识别这些能力也在快速进入企业场景。思路是把多模态能力也抽象成“模型”的一种复用现有的路由、限流、计费体系只是请求和响应的数据结构不同。另一个方向是提示词版本管理。提示词是 AI 应用的核心资产之一但很多团队还在用硬编码或者配置文件管理改一次要发一次版。我在尝试把提示词也纳入配置中心支持版本管理、灰度发布、A/B 测试。这样产品经理改提示词不用等开发排期效率提升明显。还有一个方向是质量评估的自动化。现在模型返回质量主要靠人工抽检成本高且覆盖不全。我在探索用一个小模型做自动评估对每次返回打分低分样本自动进入人工复核队列。这个能力如果做成了对业务方的价值会很大。最后分享一个小技巧搭底座的时候不要想着一次做全。先把最核心的鉴权、会话、路由三个能力做扎实让业务能跑起来然后再根据实际需求逐步扩展。我见过太多团队想一口气把底座做完美结果半年过去了业务还没上线。底座的迭代节奏应该跟着业务走业务需要什么就补什么这样每一步都有验证不会做无用功。
阅读完成 · 觉得有帮助?
咨询建站