2.3 Service、Ingress 与多副本会话亲和路由 第二章前面两节把权重加载起来、把 vLLM 跑成了一个 Deployment。但一个只挂在 Pod 上的推理服务,业务方是调不到的——你需要一层稳定的网络入口:把「一个 Pod」变成「一个被内网/公网稳定访问的服务地址」,并且当副本数从 1 扩到 N 时,流量能被正确摊开。这一节讲的就是 K8s 网络层:Service 怎么选、Ingress 怎么接、多副本下怎么保住会话亲和。 我踩过最典型的坑:直接把 Pod IP 告诉前端,结果发现 Pod 一重启 IP 就变,前端全挂;或者扩到 3 副本后,前端请求被轮询打到不同副本,多轮对话上下文丢失。Service 和会话亲和就是为这两个问题而生的。
第二章前面两节把权重加载起来、把 vLLM 跑成了一个 Deployment。但一个只挂在 Pod 上的推理服务,业务方是调不到的——你需要一层稳定的网络入口:把「一个 Pod」变成「一个被内网/公网稳定访问的服务地址」,并且当副本数从 1 扩到 N 时,流量能被正确摊开。这一节讲的就是 K8s 网络层:Service 怎么选、Ingress 怎么接、多副本下怎么保住会话亲和。
我踩过最典型的坑:直接把 Pod IP 告诉前端,结果发现 Pod 一重启 IP 就变,前端全挂;或者扩到 3 副本后,前端请求被轮询打到不同副本,多轮对话上下文丢失。Service 和会话亲和就是为这两个问题而生的。
Pod 是易碎的——重建、调度、扩缩都会换 IP。K8s 的 Service 是一层稳定的虚拟 IP(ClusterIP)加负载均衡,背后通过 selector 把流量转发到匹配的 Pod。无论 Pod 怎么变,Service 的地址不变,前端只认 Service。
对 vLLM 推理服务,最常用的是 ClusterIP(仅集群内可访问)配合 Ingress 对外暴露,或 NodePort / LoadBalancer 直接对外。选型要点:
我的主张:生产环境一律 ClusterIP + Ingress。不要为了省事把推理服务直接 LoadBalancer 暴露公网——既贵又难管控鉴权。
Deployment 扩到 N 副本后,Service 默认用 iptables/IPVS 把请求轮询(或随机)转发到后端 Pod。这对「无状态请求」很完美:每个请求独立,打到哪个 Pod 都行。
但 LLM 推理有个特殊点:vLLM 默认不跨请求共享 KV Cache(除非开 prefix caching)。也就是说,同一个用户的两轮对话打到不同 Pod,第二轮 Pod 没有第一轮的上下文,要么重新 prefill(慢),要么直接丢历史(错)。所以多副本下,你必须决定:是接受「每轮独立、靠应用层带历史上下文」,还是做会话亲和把同一会话绑定到固定 Pod。
解决「多轮对话丢上下文」有两条路:
sessionAffinity: ClientIP:按客户端源 IP 哈希,把同一 IP 的请求固定到同一 Pod。配置极简,但有两个硬伤:(1) 客户端在大网 NAT 后常共享一个出口 IP,导致多个用户被绑到同一 Pod,负载不均;(2) Pod 扩缩容会改变哈希环,导致大批量会话漂移。我只在对一致性要求低、且客户端 IP 真实的场景用。session_id → Pod 映射,把同一 session 的请求路由到固定 Pod。精准、不受 Pod 扩缩影响,但需要你自己写一点路由逻辑。对于「多轮对话」业务,这笔投入值得——否则用户会体验到「上一句记得、下一句失忆」的诡异 bug。我的判断:多轮对话业务,会话亲和不是可选项,是必选项。而 ClientIP 亲和只是「凑合可用」,真正稳健要应用层绑定。
Service 是集群内寻址,要对外还得靠 Ingress(运行在 Ingress Controller 上,如 nginx-ingress、Traefik)。它做几件事:
/v1/chat 路由到推理 Service,/admin 路由到别的服务。proxy-read-timeout / proxy-send-timeout 调大(如 300s+),否则长请求会在网关层被截断。一个常见翻车:Ingress 默认超时 60s,而你的推理请求平均 90s,结果所有请求在网关被断掉,Pod 明明正常却「前端全超时」。这条务必提前改。
前面 4.2 讲过 readinessProbe,这里要强调它和 Service 的联动:只有 readinessProbe 成功的 Pod,才会被加入 Service 的 endpoints。这意味着:
所以探针必须探测「真正能推理的端口/路径」,且 vLLM 要在权重加载完成后才返回成功。
把上面串起来,对外暴露 GLM-5.2 推理服务的标准动作:
session_id → Pod 绑定;否则用 ClientIP 亲和兜底。读完这一节,你应该能搭出「稳定可访问、多副本不丢上下文」的推理网络:ClusterIP Service 给 Pod 稳定门牌号、Ingress 统一收口 HTTPS 与限流并调大超时、readinessProbe 保证只有就绪 Pod 进 endpoints、会话亲和在多轮对话下保住上下文。一句话——Deployment 让服务「能跑」,Service+Ingress 让它「能被稳定调」,会话亲和让它「对话不丢记忆」。到第二章结束,你已经具备了一个可被业务方调用的完整推理服务骨架。