
Kubernetes Affinity 实战推理服务就近调度减少跨节点流量一、跨节点流量为什么是推理集群的隐性成本推理服务在 Kubernetes 集群中运行时请求链路通常经过网关层到达推理 Pod。如果网关 Pod 和推理 Pod 分布在不同节点每次推理请求都会产生跨节点网络通信。单次请求的延迟增加可能只有毫秒级但高并发场景下累计影响显著——跨节点流量占用网卡带宽TCP 连接在节点间来回跳跃可观测性数据中 P99 延迟明显高于 P50。基础设施不需要漂亮话跨节点流量就是额外开销数据可验证。在一个 20 节点的推理集群中网关随机调度导致约 60% 的推理请求跨节点执行。通过 Affinity 规则将推理 Pod 优先调度到网关所在节点后跨节点请求比例降到 15%P99 延迟下降约 30ms。Affinity 不是锦上添花而是推理集群调度策略的基础组件。推理服务对延迟敏感GPU 资源集中分布这两点决定了就近调度的必要性。二、Affinity 机制与推理调度模型Kubernetes 提供两种 AffinitynodeAffinity控制 Pod 对节点的偏好podAffinity控制 Pod 之间同节点的偏好。推理场景主要使用podAffinity让推理 Pod 和网关 Pod 尽量共处同一节点。flowchart LR subgraph NS[节点调度策略] direction TB NA[nodeAffinity: GPU 节点筛选] PA[podAffinity: 就近网关 Pod] PA2[podAntiAffinity: 同模型分散] end subgraph RG[推理网关] GW1[网关 Pod Node-A] GW2[网关 Pod Node-B] end subgraph IS[推理服务] I1[推理 Pod Node-A ✓ 就近] I2[推理 Pod Node-B ✓ 就近] I3[推理 Pod Node-C ✗ 远端] end NS -- RG -- IS style NA fill:#e3f2fd style PA fill:#fff3e0 style PA2 fill:#fce4ec style I3 fill:#ffcdd2关键参数说明参数类型推理场景用法requiredDuringScheduling硬约束必须调度到 GPU 节点preferredDuringScheduling软约束优先靠近网关 Pod无资源时允许远端topologyKey拓扑域kubernetes.io/hostname按节点topology.kubernetes.io/zone按可用区podAntiAffinity反亲和同模型副本分散到不同节点提高可用性三层调度策略的优先级硬约束必须满足软约束尽力满足反亲和避免单点。三、推理服务 Affinity 配置实现推理服务的 Deployment 配置包含三层 Affinity 策略# inference-deployment.yaml — 推理服务完整调度配置 apiVersion: apps/v1 kind: Deployment metadata: name: qwen-7b-inference namespace: ai-inference labels: app: qwen-7b-inference model: qwen-7b spec: replicas: 4 selector: matchLabels: app: qwen-7b-inference template: metadata: labels: app: qwen-7b-inference model: qwen-7b spec: affinity: # 第一层硬约束必须调度到 GPU 节点 nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: gpu-type operator: In values: - nvidia-a100 - nvidia-l40 - key: gpu-available operator: Gt # GPU 可用数量大于 0 values: - 0 # 第二层软约束优先调度到网关 Pod 所在节点 podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 80 # 高权重就近调度优先级最高 podAffinityTerm: labelSelector: matchLabels: app: inference-gateway topologyKey: kubernetes.io/hostname namespaces: - ai-inference # 第三层反亲和同模型副本分散到不同节点 podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 50 podAffinityTerm: labelSelector: matchLabels: model: qwen-7b # 同模型的 Pod 分散 topologyKey: kubernetes.io/hostname # GPU 资源声明 resources: limits: nvidia.com/gpu: 1 requests: nvidia.com/gpu: 1 cpu: 4 memory: 16Gi containers: - name: inference-server image: registry.internal.com/ai-inference/qwen-7b:v1.3 ports: - containerPort: 8000 env: - name: MODEL_DIR value: /opt/models/v1.3 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 120 # 模型加载需要时间 periodSeconds: 30 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 10网关服务也需要配置 Affinity确保网关 Pod 分布在 GPU 节点上# gateway-deployment.yaml — 推理网关调度配置 apiVersion: apps/v1 kind: Deployment metadata: name: inference-gateway namespace: ai-inference spec: replicas: 3 selector: matchLabels: app: inference-gateway template: metadata: labels: app: inference-gateway spec: affinity: # 网关优先调度到有推理 Pod 的节点 podAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 70 podAffinityTerm: labelSelector: matchLabels: app: qwen-7b-inference topologyKey: kubernetes.io/hostname namespaces: - ai-inference # 网关副本分散 podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 40 podAffinityTerm: labelSelector: matchLabels: app: inference-gateway topologyKey: kubernetes.io/hostname containers: - name: gateway image: registry.internal.com/ai-inference/gateway:v2.1 ports: - containerPort: 8080调度效果验证脚本#!/bin/bash # verify-affinity.sh — 验证 Affinity 调度效果 # 输出推理 Pod 和网关 Pod 的节点分布计算就近比例 echo 网关 Pod 节点分布 GW_NODES$(kubectl get pods -n ai-inference \ -l appinference-gateway -o jsonpath{.items[*].spec.nodeName}) echo 网关节点: $GW_NODES echo echo 推理 Pod 节点分布 INF_PODS$(kubectl get pods -n ai-inference \ -l appqwen-7b-inference -o jsonpath{range .items[*]}{.metadata.name}{\t}{.spec.nodeName}{end}) echo $INF_PODS # 统计就近调度比例 TOTAL0 LOCAL0 for gw_node in $GW_NODES; do INF_NODES$(kubectl get pods -n ai-inference \ -l appqwen-7b-inference -o jsonpath{.items[*].spec.nodeName}) for inf_node in $INF_NODES; do TOTAL$((TOTAL 1)) if [ $gw_node $inf_node ]; then LOCAL$((LOCAL 1)) fi done done echo echo 调度统计 echo 总推理 Pod 数: $TOTAL echo 就近调度数: $LOCAL echo 就近比例: $(echo scale2; $LOCAL * 100 / $TOTAL | bc)%四、Affinity 策略的边界与注意事项硬约束的代价。requiredDuringScheduling设置过多硬约束会导致 Pod 无法调度。推理场景中GPU 节点硬约束是必须的但必须和网关同节点不应设为硬约束——GPU 节点资源有限网关 Pod 占用后推理 Pod 可能无处可去。用软约束preferred实现就近调度硬约束只保证 GPU 资源。拓扑域选择。topologyKey用kubernetes.io/hostname是最细粒度的节点级亲和。如果集群跨多个可用区需要权衡节点级亲和降低跨节点流量但可能集中在一个可用区可用性下降。可用区级亲和topology.kubernetes.io/zone保证跨区分布但跨节点流量不可避免。推理场景通常优先节点级可用性通过副本数保证。权重调参。Affinity 的weight取值 1-100多个软约束之间按权重比例分配优先级。推理场景中就近网关的权重建议设为 80分散副本的权重设为 50。权重不是绝对值而是相对比例实际效果取决于集群资源分布。调参方法先部署观察调度分布再根据数据调整权重。动态调度问题。Affinity 只在调度时生效运行中不迁移 Pod。如果网关 Pod 因节点故障迁移到新节点推理 Pod 不会自动跟随。解法是结合 Descheduler 定期重平衡或者使用拓扑感知路由Topology Aware Routing在 Service 层面优先同节点路由。五、总结推理服务就近调度的目标是减少跨节点网络开销降低延迟尾部分布。通过三层 Affinity 策略实现硬约束保证 GPU 资源软约束优先靠近网关反亲和分散副本。硬约束控制在最少必要的范围避免 Pod 无法调度软约束权重按实际调度数据调参拓扑域粒度根据可用性需求选择节点级或可用区级。Affinity 在调度时生效运行中不迁移 Pod动态场景需配合 Descheduler 或拓扑感知路由。调度策略的价值用跨节点比例和延迟数据验证而非理论推演。