AI 云原生服务的第一版:先做清流量边界和故障隔离 AI 云原生服务的第一版先做清流量边界和故障隔离本文用可复现的示例场景说明排查和设计方法阈值、容量与超时设置需要结合实际流量、依赖版本和压测结果确认不能直接照搬。服务网格刚接入大模型推理服务时踩过的第一个坑往往出在 HTTP/2 长连接与流式响应SSE的控制上。团队最初希望把鉴权、限流、Token 消耗统计和动态路由全部压进 Envoy Sidecar 里结果上线第一天Pod 内存就被缓冲的响应体撑爆同时由于长连接没配置合理的 MaxConnectionAge导致扩容出来的推理节点根本分不到流量。第一版架构如果试图面面俱到最后大多以运维灾难告终。在资源有限、业务快速迭代阶段智能服务网格治理到底要裁剪掉哪些幻想这里梳理一下核心链路的切割策略与代码落地方案。flowchart TD Client[客户端请求] -- Gateway[Ingress Gateway / Envoy] Gateway -- ControlPlane[网格控制平面 / Dynamic Router] ControlPlane -- |熔断Token限流| EnvoySidecar[Pod Envoy Sidecar] EnvoySidecar -- |SSE 流式透传| LLMService[LLM 推理服务 Engine] EnvoySidecar -.-|异步日志上报| Collector[Token 耗时采集器]SSE 流式传输下的 Sidecar 内存挤压与连接倾斜引入 Istio 或 Envoy 管理 LLM API 时最容易被忽略的是 Envoy 的默认 Buffer 策略。标准 HTTP 接口习惯在网格侧做 Response Body 的 Parse 或鉴权但在 SSEServer-Sent Events模式下大模型生成的 Token 是逐字输出的。如果 Sidecar 试图去缓存完整的 Response或者配置了全局的 Response Buffer Filter网格会直接把流式响应变成阻塞响应延迟飙升几秒以上。更糟糕的是连接复用机制。由于大模型推理耗时长一个请求可能持续数秒甚至数十秒常规 HTTP/1.1 连接池会迅速耗尽。如果开启 HTTP/2 Multiplexing流量往往集中在少数几个先建立的 TCP 长连接上。当 Kubernetes 触发 HPA 扩容出新 Pod 时已有的连接不会自动迁移新 Pod 只能干卡着吃灰。在 EnvoyFilter 的配置中第一版应显式关闭所有响应体缓冲并强制开启基于连接年龄的优雅断开策略apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: llm-sse-passthrough namespace: ai-services spec: workloadSelector: labels: app: llm-inference configPatches: - applyTo: HTTP_FILTER match: context: SIDECAR_OUTBOUND listener: filterChain: filter: name: envoy.filters.network.http_connection_manager patch: operation: INSERT_BEFORE value: name: envoy.filters.http.router typed_config: type: type.googleapis.com/envoy.extensions.filters.http.router.v3.Router suppress_envoy_headers: false - applyTo: CLUSTER patch: operation: MERGE value: typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http2_protocol_options: max_concurrent_streams: 100代码逻辑很简单强行让 Sidecar 保持纯粹的管道角色。任何试图在 Envoy 内部做 Token 复杂计费或 Prompt 内容安全过滤的尝试在第一版都应该拒绝。这些计算密集型且带有锁竞争的操作丢给后端业务 Gateway 或专门的 Async Worker 节点才是正道。控制平面与数据平面的责任切割哪些算力绝不能下沉到 Envoy不少架构方案喜欢在 Envoy 中写 Lua 脚本或者 Wasm 插件来解析 OpenAI 兼容协议的 Request Body提取prompt_tokens和model字段做实时路由。这种做法在并发量上来之后会引发可怕的 CPU 挂起。Envoy 自身的事件循环Event Loop由 Worker 线程驱动每个 Worker 绑在一个 CPU 核心上。如果在 Envoy 内用 Lua 阻塞解析几万字的大文本 Prompt等于直接卡死了该线程上的所有其他 TCP 转发。正确的做法是把控制链路拆成三段Ingress 边缘节点只做 TLS 终止、基础 IP 限流和 HTTP 协议校验。轻量级 API GatewayGo/Java解析 JSON 参数计算 Prompt Token 数完成用户配额扣减并在 Request Header 中注入路由 Tag例如x-llm-provider: vllm-a100。Envoy Sidecar仅仅读取 Header 中的 Tag做基于权重的 Cluster 转发和 Canary 灰度。在 Go 语言实现的 API Gateway 路由层中我们可以看到非常清晰的轻量化处理逻辑package router import ( net/http strings ) type LLMHeaderRouter struct { targetHeader string } func NewLLMHeaderRouter() *LLMHeaderRouter { return LLMHeaderRouter{targetHeader: x-llm-model-tier} } func (r *LLMHeaderRouter) ServeHTTP(w http.ResponseWriter, req *http.Request, next http.HandlerFunc) { modelName : req.Header.Get(x-requested-model) // 根据模型算力需求强行分类避免 Envoy 解析 Body switch { case strings.HasPrefix(modelName, gpt-4), strings.Contains(modelName, 70b): req.Header.Set(r.targetHeader, high-perf) case strings.Contains(modelName, 7b), strings.Contains(modelName, 8b): req.Header.Set(r.targetHeader, standard) default: req.Header.Set(r.targetHeader, fallback) } next(w, req) }这段代码保证了 Envoy 无需读取包含大量字符串的 HTTP Body只需要检查一个几十字节的 Header 标记吞吐量能提升一个数量级。降级策略的边界冷启动超时与 upstream_reset 的捕获大模型服务最常出现的故障并不是 Pod 彻底崩溃而是 GPU 显存溢出OOM或者 KV Cache 满了之后的极端卡顿。这时候请求卡在 API Engine 里 Envoy 默认的 Timeout比如 15 秒会直接触发upstream_reset_before_response_started。如果在服务网格中开启了无脑重试Retry Rules极端情况下会形成放大效应一个耗时 10 秒的卡顿请求重试 3 次把后面的实例全数拖垮。第一版的重试机制应收紧到极小的范围只重试连接建立失败Connect Timeout与 503 状态码。对于已经开始返回 SSE header 的请求严禁任何形式的自动重试。针对模型加载的冷启动在 VirtualService 中配置阶梯式 Timeout。针对 Istio 治理规则的定制如下apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: llm-model-route namespace: ai-services spec: hosts: - llm-service.ai-services.svc.cluster.local http: - match: - headers: x-llm-model-tier: exact: high-perf route: - destination: host: llm-service.ai-services.svc.cluster.local subset: vllm-cluster weight: 100 timeout: 120s retries: attempts: 2 perTryTimeout: 3s retryOn: 503,connect-failure,refused-stream retryRemoteLocalities: false这里的perTryTimeout: 3s配合connect-failure是保护后端的关键如果 3 秒内连 TCP 都握不上手说明该节点繁忙或崩溃迅速切走但如果已经建立连接就允许它执行最多 120 秒绝不中途打断造成显存浪费。第一版交付的指标底线与落盘取舍评估第一版 AI 云原生网格是否合格不用看那些花里胡哨的智能调度算法看这四个指标就能定生死TTFTTime to First TokenP99 延迟网格引入的额外开销是否控制在 5ms 以内。连接平滑度HPA 缩容时Sidecar 是否能通过GOAWAY帧平滑切断长连接避免客户端收到ECONNRESET。内存占用线Sidecar 进程在持续高并发流式输出下RSS 内存是否稳定在 100MB 梯队没有呈现线性上升趋势。日志不上锁Token 统计异步刷入 Kafka/Logtail网格数据面只写 Trace ID绝不挂起主数据流。先把这一套最简但扎实的治理方案部署上线让系统在真实的线上流量里跑上两周。拿着实际产生的 Prometheus 指标和 Grafana 监控曲线再去谈真正的动态权重路由与基于 GPU 显存使用率的自定义 Envoy 调度器。架构不是越复杂越好能扛住线上的抖动才是第一版真正的底线。