开发者生态
morning
业界首次:DeepSeek-V4 基于国产AI芯片+SGLang RBG的云原生推理方案在招商银行落地
2026-06-10
1 阅读
招行信息技术部
作者 | 招商银行信息技术部 - 架构管理团队 技术方向 | AI 基础设施、大模型推理优化 大模型推理正在从单机走向分布式集群和分离式架构,但 Kubernetes 原生的工作负载原语(Deployment、StatefulSet)并不是为"多角色协作、拓扑敏感、快速和可靠升级、故障联动"的推理场景设计的。本文介绍招商银行基于 SGLang RBG 组件,在国产 AI 芯片上落地 DeepSeek-V4 Flash 大 EP 推理服务的实践,重点剖析动态端口分配、服务发现、多级故障自愈与原地升级四个核心机制的设计与实现。 问题:DeepSeek-V4 国产 AI 芯片大 EP 部署的挑战 当模型参数量达到数百 B 级别,单机已无法承载完整的推理计算。以 DeepSeek-V4 Flash 为例,它采用 MoE(Mixture of Experts)架构,专家参数分布在多张卡上通过 EP(Expert Parallelism)并行计算;同时,为了提升吞吐和降低延迟,业界通常将推理过程拆分为 Prefill(预填充)和 Decode(解码)两个阶段,分别由不同的实例组承担,再通过 Router 统一调度请求——这就是所谓的 PD 分离 + 大 EP 架构。 这个架构在算法和系统层面已经成熟,但在基于 Kubernetes 纳管异构算力卡时,其部署与运维面临的工程化挑战,在复杂度上远超传统的无状态微服务。以下,我们将这些痛点按层次进行系统性剖析。 多角色拓扑的配置复杂度 大 EP 部署本质上是一个 三级嵌套的拓扑结构:最外层是角色(Router、Prefill、Decode),中间层是每个角色的多个实例(如 2 个 Prefill 实例组),最内层是每个实例内的多个 Worker Pod(如一个 Prefill 实例跨 16 张 AI 芯片,由 1 个 Leader + 15 个 Worker 组成)。 传统 Kubernetes 的工作负载原语无法自然表达这种结构:Deployment 是无状态的,不支持 Pod 间的拓扑关系;StatefulSet 只管理单一角色的有序副本,无法表达跨角色的依赖。因此运维人员不得不手动维护三组独立的 YAML 配置,并在其中硬编码角色间的网络引用关系——Router 的启动命令里要列出所有 Prefill 和 Decode 的地址,Prefill 的配置里要写明数据传输对端 Decode 的地址。 以一个 2 Prefill + 2 Decode 的部署为例,仅 Router 的启动参数中就需要写入 32 个 --prefiller-hosts 和 32 个 --decoder-hosts 条目(每个实例 16 张卡各一个端点)。这些地址一旦写错或遗漏,轻则部分专家不可达导致推理精度下降,重则整个服务无法启动。 hostNetwork 下的端口管理 在大 EP 部署中,Prefill 和 Decode 之间的 KV Cache 传输对带宽和延迟极其敏感,通常需要使用 RDMA 实现高速数据通道。这要求 Pod 以 hostNetwork: true 模式运行,直接使用宿主机网络栈。 hostNetwork 模式带来两个层面的端口管理问题: 第一是 同节点端口冲突。每个推理 Pod 至少需要占用 3-4 个端口(HTTP API 端口、gRPC 通信端口、数据传输端口、指标暴露端口)。如果调度器将两个推理 Pod 放在同一节点上,硬编码的端口号必然冲突。传统做法是通过 nodeSelector 或反亲和性保证每个节点只跑一个推理 Pod,但这牺牲了资源灵活性和弹性伸缩能力。 第二是 跨角色的端口发现。即使端口不冲突,Router 也需要知道每个 Prefill/Decode Pod 实际监听的端口号。在端口硬编码的方案下这不是问题,但一旦引入动态端口分配(解决冲突后的必然选择),Router 如何获知每个下游节点的端口就成了新的挑战——传统的 Kubernetes Service 在 hostNetwork 模式下并不能很好地工作。 服务发现的时序依赖 即便不考虑端口问题,大 EP 部署中的服务发现本身也比普通微服务复杂得多。 首先是 启动顺序依赖。EP 并行要求同一实例内的所有 Worker 必须在通信组建立阶段(HCCL/NCCL init)同时就绪;Prefill 和 Decode 节点需要互相发现后才能建立 KV Cache 传输通道;Router 则需要等待所有下游节点就绪后才能正确路由。这些依赖关系不是简单的"先启动 A 再启动 B",而是多层嵌套的拓扑感知。 其次是 地址解析的竞态问题。若节点间的地址发现依赖启动脚本执行 DNS 查询(如 getent hosts),会面临明显的时序风险:Kubernetes 中 DNS 记录的刷新依赖目标 Pod 变为 Ready 状态。如果查询发生在目标 Pod 就绪之前,将导致解析失败或获取到陈旧(Stale)地址。在 Pod 动态扩缩容或漂移重启场景下,这种竞态条件极易引发节点的级联启动失败。 故障域的级联效应 大 EP 架构中的故障传播路径比单体服务复杂得多,呈现出 三级级联 的特征(如:NPU 场景下集合通信库为 HCCL,GPU 场景下对应 NCCL,下文统称"集合通信库"): 实例内级联。一个 EP 实例(如 Prefill-0)由多个 Worker Pod 组成,它们通过集合通信库(HCCL/NCCL)建立 communicator 协同计算。这类集合通信库本身 不具备容错能力——任何一个 Worker 故障都会导致 collective 操作阻塞或失败,整个通信组进入不可用状态,且原生不支持单 rank 的 “hot rejoin”。Kubernetes 原生的 Pod 级重启只会重启出问题的那个 Worker,但它重启后需要与其他 Worker 一起销毁旧 communicator 并重新建组——如果其他 Worker 不感知到这次中断并配合重置状态,通信组将无法恢复,重启的那个 Worker 也只能空转。 跨角色级联。Prefill 和 Decode 之间通过 Bootstrap server 注册会话、并基于 RDMA 建立 KV Cache 传输通道。需要强调的是,这里的对端关系 不是静态 1:1 配对 的——Router 按请求维度动态选择 Prefill/Decode 组合,真正"持有状态"的是 Bootstrap server 的会话注册表和 Transfer engine(如 Mooncake、NIXL)的 RDMA QP 缓存。当一个 Decode 实例故障重启后,即使它自身的推理服务恢复了: Bootstrap server 上残留的旧 worker 注册记录、Transfer engine 上残留的 RDMA QP 握手缓存,不会随 Pod 重启而自动清理;其他 Prefill 实例新发起的 KV 传输会因为会话 ID 不匹配或 QP 失效而失败,表现为"对端在线但传输始终建立不起来";更上游的 Router 如果不感知 Decode 的状态变化,还会继续将新请求路由