东方智慧AI 算力
AI算力 · 昇腾部署课件 D5

昇腾部署第 D5 课:可用性、健康与调优——起来之后怎么活下去

2026-10-05

编制:观澜|日期:2026-10-05|级别:T2 标准级 层级:D 层 · L3 服务(D 层第 5 课,D 层收官;前接 D4《PD 分离与混部》) 素材来源:昇腾官方 MindIE 3.1.0 文档(《基于 K8s 多容器 PD 分离服务部署》含特性配置指导与附录·运维技巧、《虚推健康探测》特性说明、《主备倒换特性》、《就绪状态查询接口》、MindIE Motor CPP 开发指南《集群内通信接口》) 数据纪律:配置项、参数、官方报错文本、注意事项逐字出自官方文档;标注「归纳」的是便于记忆的整理,非官方口径。


第一段 · 章前定位

D2 讲的是"怎么让服务起来",D3 讲"由哪些角色组成",D4 讲"为什么这么拆"。

这一课解决最后一类问题:

服务起来了,然后呢?

真实生产里,"起来了"只是开始:

问题 谁关心
一台服务器挂了,服务还能用吗? 可用性
某些进程卡死了,但服务"看起来正常"怎么办? 健康探测
突然来十万个请求,服务会被压垮吗? 过载保护
同样一批卡,怎么让吞吐更高? 调优

这一课就是讲这四件事。

⭐ 而且好消息是:官方把答案都做好了,并且在示例配置里默认开了 —— 你要学的不是"怎么开",而是"它是什么、什么时候该调"。

这一课也把 A0 的判据 ④ 补完: 判据 ④ 是"端口 + curl 服务起得来"。 D2 讲了"起得来",这一课讲"起得来之后,怎么知道它还好着"。


第二段 · 学习目标

学完这一课,你应该能回答:

  1. 官方全量配置示例默认开启了哪六项能力
  2. 主备倒换解决什么、开启的前置条件是什么
  3. 虚推健康检查是什么、它针对的"静默故障"是什么样
  4. 服务限流怎么配、参数是什么意思
  5. KV Cache 亲和调度与 KV 池化分别在优化什么
  6. 服务"没就绪"时官方给的报错文本是什么
  7. 上线巡检要看哪几个指标(就绪码 / GET /status / GET /health / AI Cube 利用率)
  8. 这几条官方命令:kubectl get pods -o wide、/v1/readiness、bash show_log.sh、npu-smi info watch -s u

第三段 · 官方默认开了哪六项(总览)

官方原文(特性配置指导一节的开头):

上文 user_config.json 与 env.json 全量示例已默认开启 主备倒换、异常实例重启、服务限流、虚推、KV 亲和性调度、KV 池化等能力。 若只需调整某项能力,可对照本节做最小配置修改。

六项能力分类(归纳)

分类 能力 解决什么
可用性与自愈 主备倒换 服务器级故障
异常实例重启 实例级故障
保护与探测 服务限流 过载
虚推健康检查 静默故障
性能调优 KV Cache 亲和调度 重复前缀的重复计算
KV 池化 显存压力

⭐ 注意官方那句话的语气:「全量示例已默认开启」 —— 这意味着你拿官方示例跑起来时,这六项已经在工作了。 所以你遇到的现象(例如"没请求时它也在动")可能正是虚推健康检查在干活。

这是一条很实用的排障提示: 在看日志发现"莫名其妙的行为"时,先想想这六项里有没有哪一项会表现成这样。


第四段 【如果我来做】一条真实的上线执行路径

这一节是本课的核心。 前三段讲的是"官方默认开了哪六项能力",这一节讲: 如果现在把"让服务活下去"这件事交给我,我从哪里开始、按什么顺序做、每一步凭什么判断。 本课本身就是讲可用性与调优,所以这条路径写得最实 —— 巡检 → 看指标 → 定位异常 → 调优。

4.0 先记住一句话:顺序错了会返工

"起来之后怎么活下去"是一条有先后顺序的链路,不是"把六项能力全开一遍就完了"。 最容易犯的错是顺序颠倒:

  • 先调优(开 KV 亲和 / KV 池化),再发现服务根本没就绪 → 拿没对准的基线去调,变量全是乱的,白调;
  • 为了排障把日志级别调成 INFO/DEBUG,结果虚推被引擎自动关掉(官方原文)→ 健康探测悄悄失效,你还不知道;
  • 看到 kubectl get pods 显示 Running 就以为万事大吉 → 官方原文: "Pod 状态为 Running 仅表示已成功调度并启动,是否业务就绪仍需结合日志进一步确认" —— 这是本课最容易踩的坑。

所以我的顺序是:摸底 → 建健康检查 → 定日志级别 → 认静默故障 → 跑通基线 → 再调优 → 收口 → 出证据。


4.1 我会按这个顺序做(八步)

① 先摸底:上线前先看官方默认开了哪六项能力,别自己乱改。 ② 建健康检查:定清楚"健康"看哪几个指标(就绪码 / GET /status / GET /health / AI Cube 利用率)。 ③ 定日志级别:把 ASCEND_GLOBAL_LOG_LEVEL 定在 ERROR,否则虚推会被引擎自动关掉。 ④ 认"静默故障":记住它的长相 —— 进程卡死、服务看似无问题,并知道虚推就是为它准备的。 ⑤ 先跑通最小链路:拉起服务 + 发一次真推理,作为调优前的基线。 ⑥ 再做性能调优:基线没稳之前,不碰 KV 亲和 / KV 池化。 ⑦ 收口出证据:把 Pod 状态、就绪码、一次成功推理的返回、日志片段留下来。 ⑧ 诚实:官方没给答案的地方(例如日志的具体路径),明写"这里要自己查"。


4.2 第①步 先摸底:上线前先看官方默认开了哪六项能力

目的:在动手调之前,先把"服务在不在、官方默认开了什么"这两个事实搞清楚。

官方原文(特性配置指导开头):

上文 user_config.json 与 env.json 全量示例已默认开启主备倒换、异常实例重启、 服务限流、虚推、KV 亲和性调度、KV 池化等能力。 若只需调整某项能力,可对照本节做最小配置修改。

为什么这一步放最前面:六项能力默认已开 —— 你多改一处,就多一个变量。 "最小配置修改"是官方原话,摸底的目的就是搞清楚"哪些其实不用我动"。

命令 kubectl get pods -n <namespace> -o wide

含义:列出这个命名空间下的所有 Pod,看它们起没起、被调度到哪台机器 拆解:kubectl(K8s 命令行)+ get pods(列出 Pod)+ -n <namespace>(指定命名空间, 须与 user_config.json 里的 job_id 一致,默认 mindie-motor)+ -o wide(多显示 Pod IP 与所在节点) 用法:kubectl get pods -n mindie-motor -o wide 期望:看到这几类 Pod 且状态为 Running —— mindie-motor-controller-xxxxx(服务管理 Pod)、 mindie-motor-coordinator-xxxx(请求调度 Pod,业务入口)、vllm-px-xxxx(P 实例)、vllm-dx-xxxx(D 实例) 不过会怎样:Pod 卡在 Pending / ContainerCreating → 镜像拉不下来,或权重挂载路径不存在 (官方运维技巧:确保 image_name 在集群内可正常拉取、weight_mount_path 在宿主机上存在); 报 No resources found → 命名空间填错了,或服务根本没拉起来(回 D2/D3) ⭐ 记住官方那句话:Running 只表示"已成功调度并启动",不等于"业务就绪" —— 所以这一步只是摸底,真就绪不看这个,看下一步。


4.3 第②步 建健康检查:到底看哪几个指标

"健康"在本课里不是一个形容词,是一组可以查的指标。 官方给的口子是这几个:

层 指标 / 接口 判读
就绪面 GET /v1/readiness 200 = 已就绪;503 = 未就绪
就绪面(Triton) GET /v2/health/ready 同上(200 / 503)
引擎管理面 Node Manager 周期请求 Engine Server mgmt 面 GET /status 综合推理面 /health 与虚推结果,返回 normal / abnormal
推理面 GET /health 由 HealthCollector 探测,超时/重试由 health_collector_timeout 控制
算力面 AI Cube 利用率 虚推的判据之一(见下)

⭐ 一句话记住三层分工:就绪码证明"调度面活着",/status 证明"引擎面活着", AI Cube 利用率证明"算力面在真干活"。三样都看,才叫"建了健康检查"。

命令 curl -s -o /dev/null -w "%{http_code}\n" https://<ip>:<port>/v1/readiness

含义:只取就绪接口的 HTTP 状态码、不打印正文 —— 一把量出"就绪没就绪" 拆解:curl(发请求)+ -s(静默,不显示进度条)+ -o /dev/null(丢掉响应正文) + -w "%{http_code}\n"(只打印状态码)+ URL 取自官方就绪接口 https://{ip}:{port}/v1/readiness (官方说明:{ip} 优先取环境变量 POD_IP,取不到则取 ms_coordinator.json 的 manage_ip; {port} 优先取启动命令参数 {status_port},取不到则取 manage_port) 用法:curl -s -o /dev/null -w "%{http_code}\n" https://127.0.0.1:1025/v1/readiness 期望:打印 200 —— 官方原文:"状态码 200,表示服务已就绪,消息体没有内容。" 不过会怎样:打印 503 —— 官方原文:"状态码 503,表示服务未就绪" → 回第 ① 步看 Pod,再结合日志确认; curl: (7) Failed to connect → 地址或端口不对({ip}/{port} 取值见上面的官方说明)

命令 npu-smi info watch -s u

含义:看 NPU 的 AI Cube 利用率(虚推判断"算力面在不在真干活"用的指标) 拆解:npu-smi info watch(周期性刷新设备信息)+ -s u(只采样 u 这一项,即 AI Cube Usage) 用法:npu-smi info watch -s u 期望:能持续打印 AI Cube 利用率的数值 不过会怎样:报不支持 / 无输出 → 当前 HDK 版本太老。 官方原文:启动虚推前会通过 npu-smi info watch -h 检查 help 是否包含 u - AI Cube Usage; 若当前 HDK 不支持该指标,Engine Server 会自动关闭虚推。(官方:虚推仅支持 HDK 26.0.RC1 及以后版本)

命令 npu-smi info watch -h

含义:先查 npu-smi info watch 支持哪些采样项,确认清单里有没有 u - AI Cube Usage 拆解:-h(看帮助 / 支持的指标清单)—— 官方就是用它做虚推的前置检查 用法:npu-smi info watch -h 期望:输出里能看到 u - AI Cube Usage 不过会怎样:清单里没有 u → 虚推会被自动关闭(官方原文),得换 HDK 版本


4.4 第③步 定日志级别:别把虚推调没了

这是本课最反直觉的一条 —— 官方原文:

虚推仅允许在 ERROR 日志级别下开启(ASCEND_GLOBAL_LOG_LEVEL=3,未配置默认即为 ERROR)。 若引擎进程环境中显式配置为非 ERROR,Engine Server 启动虚推前会关闭虚推并打印 warning。

含义:你为了看得更细,把日志级别调成 INFO/DEBUG,虚推会被自动关掉 —— 而且是"打印一条 warning 就关",你多半注意不到。 结果就是:看起来一切都好,健康探测其实早没了。

命令 export ASCEND_GLOBAL_LOG_LEVEL=3

含义:把昇腾组件的日志级别设为 ERROR(3) —— 官方允许虚推开启的唯一日志级别 拆解:ASCEND_GLOBAL_LOG_LEVEL 取值 0=DEBUG、1=INFO、2=WARNING、3=ERROR(官方原文) 用法:export ASCEND_GLOBAL_LOG_LEVEL=3(未配置时默认即为 ERROR,所以"什么都不配"也是对的) 期望:echo $ASCEND_GLOBAL_LOG_LEVEL 打印 3 不过会怎样:设成 0/1/2 → 官方原文:"Engine Server 启动虚推前会关闭虚推并打印 warning", 于是配置里 enable_virtual_inference: true 形同虚设

命令 bash show_log.sh

含义:采集并持续跟踪各 Pod 的日志(官方部署指导给的日志入口) 拆解:脚本在 examples/deployer/ 下;运行前要先改 log_collect/log_config.ini 里的 name_space, 改成与 job_id 一致的命名空间;输出目录是 log_collect/log/ 用法:cd examples/deployer → vim log_collect/log_config.ini(把 name_space 换成你的命名空间)→ bash show_log.sh 期望:屏幕持续滚动各 Pod 的日志,同时在 log_collect/log/ 下生成日志文件 不过会怎样:日志空空如也 → name_space 没改对;要找关键报错, 按 Pod 名对号入座(Controller / Coordinator / vllm-px / vllm-dx)


4.5 第④步 认"静默故障":最危险的一类

官方原文:

静默故障表现为:部分进程卡死,服务看似无问题,但无法正常推理。

为什么它最危险(归纳):它会骗过"端口通不通"这一层。

普通故障 静默故障
端口 不通 通
进程 不在 在
kubectl get pods 不是 Running Running
表面 明显异常 "看似无问题"
实际 起不来 无法正常推理

官方的对策就是"虚推"(第五段详述): 业务流量较小时发送轻量级推理请求;业务流量较大时查看 NPU 计算核心使用率。 不健康的 P/D 实例会被重启以消除静默故障。

⭐ 本课最该带走的一句验收话: "端口通 / Pod Running"只能证明调度面活着;"能推理"必须主动发一个请求去证明。


4.6 第⑤步 先跑通最小链路(基线),再谈调优

没跑通基线就调优,等于没量尺子就裁衣服。 官方给的验证请求是这一条:

命令 curl -X POST http://<master_node_ip>:31015/v1/chat/completions -H "Content-Type: application/json" -d '{"model":"<served_model_name>","messages":[{"role":"user","content":"who are you?"}],"max_tokens":36,"stream":true}'

含义:向推理入口发一次真实对话请求 —— 这是"能推理"的直接证据 拆解:-X POST(用 POST)+ -H "Content-Type: application/json"(声明 JSON 体) + -d '{...}'(请求体:model 填 user_config.json 里的 served_model_name, messages 是对话,max_tokens 限长,stream: true 走流式);端口 31015 是官方样例里的入口端口 用法:把 <master_node_ip> 换成 master 节点 IP、<served_model_name> 换成配置里的值,照抄官方样例 期望:返回流式 JSON —— 官方原文:"返回流式 JSON:推理正常。" 不过会怎样:返回 {"detail":"Service is not available"} → 官方原文:"服务尚未就绪,稍后重试" (运维技巧补充:"多为 P/D 或 Coordinator 尚未完全就绪;等待后重试,并查看各 Pod 日志"); 一直 curl: (7)/(28) → 连不上,回第 ① 步


4.7 第⑥⑦⑧步 调优 / 收口 / 出证据 / 诚实

⑥ 再做性能调优(归纳):基线稳了才动手。 - 前缀重复多 → 开 KV Cache 亲和调度(第六段); - 显存压力大 → 上 KV 池化(第六段); - 官方运维技巧提醒:Prefix Cache 默认开启。要做基线性能测试,得先在 engine_config 里加 "no-enable-prefix-caching": true(vLLM)或 "disable_radix_cache": true(SGLang)—— 否则你测出来的"性能"里混着缓存的功劳。

⑦ 收口 / 出证据(归纳):用完整流程跑一遍当验收。

留下什么 从哪来
Pod 清单与状态(kubectl get pods -n <ns> -o wide) 第 ① 步
就绪码 200 第 ② 步
一次成功推理的流式返回 第 ⑤ 步
日志片段(log_collect/log/) 第 ③ 步

终止服务(官方命令):cd examples/deployer && bash delete.sh <namespace> —— 停服务要走官方卸载脚本,不要手工 kill(D2 讲过 kill -2 是进程级的优雅停止; 集群场景该走 Deployment / 卸载脚本)。

⑧ 诚实(归纳):官方没给答案的地方,明写"这里要自己查": - 日志的具体路径与收集方式 → 官方指向部署工具的 log_collect/,路径细节以官方文档与 E1 为准; - KV 池化的完整参数 → 官方明说"参数较多,篇幅有限",指向《KV 池化部署指南》; - 限流阈值设多少合适 → 官方只给了一个示例值(max_requests: 10000 / window_size: 60), 合理值要按你自己的 QPS 算。

4.8 附:本段涉及的官方原文(可用性与自愈)

下面这两项是"六项能力"里的可用性与自愈部分,官方在《特性配置指导》里给的就是这些: 它们默认已开,你主要是"知道它是什么、现象长什么样、什么时候该调"。

① 主备倒换

官方原文:

创建多个 Controller 和 Coordinator 并运行在不同的服务器上, 当某一台服务器出现异常(宕机、重启、维护升级), 部署于其他服务器的 Controller 和 Coordinator 组件将接管集群, 避免单个服务器异常导致业务请求无法调度。

原理:创建多个管理面和业务面的 Pod,分布于多台服务器。 当主 Pod 异常时,选择一套备份 Pod 承担当前业务。对外表现上整个服务集群没有任何异常。

开启方式(官方原文):

"motor_controller_config": {
  "standby_config": { "enable_master_standby": true }
},
"motor_coordinator_config": {
  "standby_config": { "enable_master_standby": true }
}

关闭:删除 standby_config 配置块,或把 enable_master_standby 设为 false。

⭐ 官方给的注意(前置条件):

须提前部署 etcd(建议 3 副本)。

官方《主备倒换特性》补的限制与约束(原文要点):

约束 官方原文
节点分布 主、备 Controller 节点不建议部署在同一台节点上
etcd 版本 ETCD 服务端需要使用 v3.6 版本
etcd 副本 服务端至少需要 3 个副本,以保证 ETCD 集群的可靠性
复用 Coordinator、Controller 主备倒换特性可以共用一套 ETCD;多套大 EP 集群也可共用,通过命名空间区分

归纳:主备倒换依赖 etcd 做协调 —— 所以"开了这个开关但没部署 etcd",它是起不来的。

⭐ 加速硬件故障恢复(官方可选步骤):硬件故障(如机器重启)时,K8s 可能无法迅速感知 Pod 状态, 官方给了加速恢复的可选步骤 —— 先查 K8s 节点心跳超时标记阈值:

命令 kubectl describe pod <kube-controller-manager-pod 名> -n kube-system | grep "node-monitor-grace-period"

含义:查 K8s 管理节点的 node-monitor-grace-period(节点心跳超时标记阈值) 拆解:kubectl describe pod <名> -n kube-system(看 kube-system 里那个 controller-manager Pod 的详情) + | grep "node-monitor-grace-period"(只挑出这一行) 用法:kubectl describe pod kube-controller-manager-node-97-10 -n kube-system | grep "node-monitor-grace-period" 期望:打印出 --node-monitor-grace-period=...(官方原文:"如果结果为空表示为默认值") 不过会怎样:查不到这个 Pod 名 → 先用 kubectl get pods -n kube-system 找到 kube-controller-manager 的 Pod ⭐ 官方给的可选做法是把该值改小(示例为 20s)以加快业务恢复 —— 改法是编辑控制平面节点上的 /etc/kubernetes/manifests/kube-controller-manager.yaml,再 systemctl restart kubelet.service。这一步属集群管理动作,不确定就别在生产上动。

② 异常实例重启

官方原文:

P/D 实例出现异常时,重启推理实例,避免实例长时间处于异常状态,影响集群推理功能。

原理:推理主进程异常退出等情况时,Motor 自动重启对应实例。 重启期间吞吐能力下降,重启后恢复正常。

开启:默认开启,无需额外操作。 关闭:无需关闭。

归纳这条的实用价值: 如果你的服务"偶尔卡一下又好了",可能就是这个机制在工作 —— 某一侧实例异常退出 → 自动重启 → 期间吞吐下降 → 恢复。 这与"服务彻底挂了"是完全不同的现象,排查方向也不同。

与 D3 的一个呼应(归纳): D3 提到 Controller 和 Coordinator 官方方案里是"单 Pod" —— 单 Pod 就是单点。 主备倒换正是给这两个控制面组件加冗余 —— 这也解释了 D3 里为什么官方单独强调 Controller 的 "RAS 能力决策"。


第五段 · 保护与探测(服务限流 / 虚推健康检查)

① 服务限流

官方原文:

限制推理入口 Coordinator 在单位时间内的最大请求数,防止服务过载。

原理:Coordinator 记录一段时间内接收到的请求数量,达到阈值后停止接收外部请求。

配置(官方原文):

"motor_coordinator_config": {
  "rate_limit_config": {
    "enable_rate_limit": true,
    "max_requests": 10000,
    "window_size": 60
  }
}

官方对这三个字段的解释:

上述配置表示 60 秒内最多处理 10000 条请求。

拆解(归纳):

字段 含义
enable_rate_limit 是否开启
max_requests 窗口内最大请求数
window_size 窗口大小(秒)

关闭:删除 rate_limit_config 配置块,或把 enable_rate_limit 设为 false。

⭐ 一个很实用的定位结论(归纳): 限流的动作发生在 Coordinator(官方:"限制推理入口 Coordinator")—— 所以如果你的请求被拒 / 变慢,而各实例都健康,先看 Coordinator 的限流配置。

⚠️ 官方没给的:阈值设多少没有标准答案 —— 官方只给了一个示例(10000 / 60s)。 该设多少要按你自己的业务 QPS 和单实例吞吐算,这里没有官方公式。

② 虚推健康检查(本课最有价值的一项)

官方原文:

虚推健康检查(Virtual Inference Health Check):探测服务健康状态,避免静默故障带来业务损失。

静默故障表现为:部分进程卡死,服务看似无问题,但无法正常推理。

原理:业务流量较小时发送轻量级推理请求; 业务流量较大时查看 NPU 计算核心使用率。 不健康的 P/D 实例会被重启以消除静默故障。

⭐⭐ "静默故障"这个定义值得单独记住:

部分进程卡死,服务看似无问题,但无法正常推理。

归纳这类故障为什么最危险(归纳):

普通故障 静默故障
端口 不通 通
进程 不在 在
表面 明显异常 "看似无问题"
实际 起不来 无法正常推理

A0 的判据 ④ 是"端口 + curl 服务起得来" —— 但静默故障恰好能骗过"端口通不通"这一层。 这正是为什么需要"虚推":主动发一个轻量推理请求去试。

⭐ 一条很实用的验收思路(归纳): "端口通"只能证明网络层活着;"能推理"要主动发一个请求去证明。 这与 D2 里官方那句"错误响应或空补全不能确认推理成功"是同一个道理。

配置(官方原文):

"motor_engine_prefill_config": {
  "health_check_config": {
    "enable_virtual_inference": true,
    "npu_usage_threshold": 10
  }
}

官方提醒:

P 和 D 实例需要单独开启虚推功能(P 的开启方式如上,D 实例的开启方式相同)。

⚠️ 一条很容易踩的官方注意:

虚推仅允许在 ERROR 日志级别下开启(ASCEND_GLOBAL_LOG_LEVEL=3,未配置默认即为 ERROR)。 若引擎进程环境中显式配置为非 ERROR,Engine Server 启动虚推前会关闭虚推并打印 warning。

归纳这条的实用含义: 如果你为了排障把日志级别调细了(调成 INFO/DEBUG),虚推会被自动关掉 —— 而你多半不会注意到那条 warning。 所以"调完日志级别之后健康探测失效了"这件事,是有官方依据的。

虚推的"机关"(官方《虚推健康探测》特性说明,原文要点)

启用条件(须同时满足,官方原文):

  1. engine_type 为 vllm —— SGLang 引擎即使配置 enable_virtual_inference: true 也会在运行时被自动关闭;
  2. health_check_config.enable_virtual_inference 为 true;
  3. 进程环境变量 ASCEND_GLOBAL_LOG_LEVEL 为 ERROR(3);
  4. 0 < health_check_config.npu_usage_threshold <= 100;
  5. 推理面 GET /health 返回正常(由 HealthCollector 探测);
  6. 仅 DP rank 0 执行虚推(非 DP0 节点运行时自动关闭)。

虚推请求长什么样(官方原文):向推理面 POST /v1/completions, 请求体为 prompt: "1"、max_tokens: 1 —— 这就是"轻量级推理请求"的真身。

NPU 负载采样:使用 npu-smi info watch -s u 采集 AI Cube 利用率。

动态探测间隔(官方原文):

AI Cube 利用率峰值(5 秒采样窗口) 下一轮间隔
≥ 80% 20 秒
< npu_usage_threshold 5 秒(默认)
[npu_usage_threshold, 80%) 保持当前间隔不变

异常判定(官方原文):当 AI Cube 利用率峰值低于 npu_usage_threshold 且虚推请求失败时, 累计连续失败次数;达到 max_failure_count 后,GET /status 返回 abnormal 且虚推循环停止。 Node Manager 的 HeartbeatManager 连续 5 次收到 abnormal 后触发自杀重调度。

配置字段全表(官方原文):

配置项 类型 默认值 说明
enable_virtual_inference bool false 虚推总开关。仅支持 vLLM;仅允许在 ERROR 日志级别下开启
npu_usage_threshold int 3 AI Cube 利用率阈值(%)
max_failure_count int 6 连续虚推失败次数上限
health_collector_timeout int 5 推理面 /health 探测超时(秒)
health_collector_timeout_retry_attempts int 3 推理面 /health 超时重试次数(含首次,仅超时触发)

⚠️ 一处官方口径差异(如实标注): 《虚推健康探测》特性说明里 health_check_config 的默认值是 false(默认关闭); 而《PD 分离服务部署指导》说全量示例已默认开启虚推。 两处口径不同 —— 到底开没开,取决于你用的是哪份示例配置,上线前一定要自己看一眼配置文件。

官方未给出的:虚推那条 warning 的原文格式与具体日志路径本课未搬运, 以官方《虚推健康探测》特性说明为准。


第六段 · 性能调优(KV Cache 亲和调度 / KV 池化)

① KV Cache 亲和调度

官方原文:

将具有相同前缀的请求调度到同一实例,复用已有 KV Cache,减少 Prefill 耗时。

原理:MindIE Motor KV Cache 亲和性调度能力依赖 Mooncake 社区的 Mooncake Conductor 组件, 允许调度器根据 KV Cache 位置优先将请求调度到缓存了对应 KV 的实例, 从而减少 KV Cache 跨实例传输开销,提升推理吞吐与响应速度。

⭐ 用 D4 的知识解释它在优化什么(归纳):

D4 讲过:Prefill 是计算密集型的,且"每个新输入序列都需执行一次 Prefill"。

那么多轮对话会怎样?(归纳) 每轮对话的前面部分是一样的(相同前缀) —— 如果每次都重新 Prefill 一遍,就是重复计算。

KV Cache 亲和调度的做法:把前缀相同的请求送到"已经算过这段前缀"的那个实例上, 让它直接复用已有的 KV Cache,不用重算。

开启方式(官方原文,三处一起改):

"motor_coordinator_config": {
  "scheduler_config": { "scheduler_type": "kv_cache_affinity" }
},
"motor_engine_prefill_config": {
  "engine_config": {
    "kv-events-config": {
      "publisher": "zmq",
      "enable_kv_cache_events": true,
      "endpoint": "tcp://*:5557",
      "topic": "kv-events",
      "replay_endpoint": "tcp://*:6667"
    },
    "enable-prefix-caching": true
  }
},
"kv_conductor_config": {
  "kvevent_instance": { "mooncake_master": { "type": "Mooncake" } },
  "http_server_port": 13333
}

归纳这三处分别在干什么: 1. motor_coordinator_config:换调度器 → scheduler_type: "kv_cache_affinity"; 2. motor_engine_prefill_config:开启 KV 事件发布(enable_kv_cache_events)+ 开启 prefix cache 特性(enable-prefix-caching); 3. kv_conductor_config:KV Conductor 配置,与 motor_engine_prefill_config 同层级。

注意(官方原文):

需要确保镜像中已安装 KV Conductor 组件。

归纳:又是"先确认东西在不在,再谈配置" —— 和 B2(ops 包)、C1(版本对应)、D2(镜像标签)同一条纪律。

② KV 池化

官方原文:

通过 MultiConnector 将 KV 缓存卸载到共享池,支持跨实例复用,降低显存压力。

原理:允许 P/D 实例通过 KV 缓存池共享 KV Cache, P 实例将计算好的 KV Cache 推入缓存池,D 实例从缓存池拉取并复用, 从而在 PD 分离场景下提升显存利用率和推理吞吐。

⭐ 这一条正好把 D4 的"代价"接上了(归纳):

D4 说:PD 分离的代价是 KV Cache 必须在 P 和 D 之间传输。 KV 池化做的就是"把这件事做得更高效" —— 不是点对点传,而是放到一个共享池里,按需取用。

配置:官方说明"参数较多,篇幅有限",指向 《KV 池化部署指南》。 关闭:改用非 MultiConnector 的单一 connector,并删除根节点 kv_cache_pool_config。

⚠️ 数据纪律提示:官方明确指出该功能"参数较多",本课不搬运完整配置, 以官方《KV 池化部署指南》为准。

③ 调优前的一个官方前提:Prefix Cache 默认开着

官方运维技巧原文:

Prefix Cache 对性能测试的影响:Prefix Cache 默认开启。 若需基线性能,可在 engine_config 中增加 "no-enable-prefix-caching": true(vLLM) 或 "disable_radix_cache": true(SGLang)。

归纳:"KV 亲和调度"和"Prefix Cache"是两件事 —— Prefix Cache 让同一实例自己复用前缀;KV 亲和调度让"该去哪台实例"也复用了前缀。 但两者都会让你的性能测试结果"更好看" —— 要做干净基线,就得先把它们关掉再测。


第七段 · 起停与"就绪"判断

官方给的运维技巧(原文,含一条真实报错)

服务未就绪:推理接口返回 {"detail":"Service is not available"} 时, 多为 P/D 或 Coordinator 尚未完全就绪;等待后重试,并查看各 Pod 日志。

⭐⭐ 这是本课最实用的一条 —— 因为它给了一个"照抄就能用"的排查映射:

你看到 官方说多半是 该做什么
推理接口返回 {"detail":"Service is not available"} P/D 或 Coordinator 尚未完全就绪 等待后重试 + 查看各 Pod 日志

归纳:"服务未就绪""服务坏了""静默故障"是三件事: - 未就绪 → 等一会儿可能就好了(实例在启动、在重启、在主备切换) - 静默故障 → "看着是好的"(Running、端口通),其实推不出结果 —— 第三种状态,本课新增 - 坏了 → 等多久都不会好

先分清这三种,能省掉大量无效排查。

⭐ 三态怎么用命令认出来(把第四段的命令放这儿对照)

命令 curl -s -o /dev/null -w "%{http_code}\n" https://<ip>:<port>/v1/readiness

含义:用就绪码区分"未就绪"和"已就绪" 拆解:同第四段(-w "%{http_code}" 只取状态码);URL 是官方就绪接口 用法:curl -s -o /dev/null -w "%{http_code}\n" https://127.0.0.1:1025/v1/readiness 期望:200 = 已就绪;503 = 未就绪(官方原文) 不过会怎样:拿到 200 但推理仍失败 → 说明"就绪"骗不了你,往"静默故障"查(第五段虚推); 连接失败 → 地址 / 端口错(回第四段)

命令 bash delete.sh <namespace>

含义:终止 / 卸载服务(官方部署指导给的收尾命令) 拆解:脚本在 examples/deployer/ 下;<namespace> 与 job_id 一致 用法:cd examples/deployer && bash delete.sh mindie-motor 期望:服务被卸载,kubectl get pods -n <namespace> 下的 Pod 逐步消失 不过会怎样:名字填错 → 报找不到命名空间;停之前先确认这里跑的不是你在意的业务 ⭐ 官方运维技巧:部署失败时,"可先按终止服务小节的命令卸载,排查并修改配置后重新部署"

起停与"看什么日志"

结合 D3 的角色分工,可以整理出一张"看哪儿的日志"的表(归纳):

现象 看谁的日志
请求进不来 / 被限流 Coordinator
接口报未就绪 P/D 实例 + Coordinator(官方原文)
某节点上的进程反复重启 NodeManager(D3:管节点级进程与健康)
主备切换相关 Controller(+ etcd)
推理结果异常 / 疑似静默故障 EngineServer / 引擎日志(往下走 D2/C 层)

官方给的日志入口是 bash show_log.sh(第四段第 ③ 步),采集到 log_collect/log/。

⚠️ 说明:上表是归纳(基于 D3 的组件职责); 具体的日志路径与收集方式以官方文档为准(E1 讲过日志分三处)。

优雅停止(回顾 D2)

D2 讲过官方的 kill -2(等同于 Ctrl+C)—— 本课补充一句(归纳): 在集群场景,停服务不要直接杀进程, 官方方案里 P/D 是 Pod、有 NodeManager 管进程 —— 该走 Deployment / 配置的启停方式(如官方 bash delete.sh),而不是手工 kill。


第八段 · 出问题怎么查

先按"六项能力"照镜子

因为官方默认全开了,很多现象是这些能力在正常工作(归纳):

你看到的现象 可能是 该做什么
服务偶尔"卡一下"又好了 异常实例重启在起作用 查日志确认,并查实例为何异常
没请求时日志里也有动作 虚推健康检查在探测 正常
请求被拒 / 变慢,但实例都健康 服务限流(Coordinator) 调 max_requests / window_size
调细日志级别后健康探测失效 虚推只在 ERROR 级别允许(官方原文) 恢复日志级别
某台机器挂了但服务没断 主备倒换在工作 正常(但要修那台机器)
想上 KV 亲和调度但起不来 镜像里有没有 KV Conductor 组件 换镜像 / 确认组件
返回 Service is not available 未就绪(官方原文) 等待重试 + 看 Pod 日志
Pod Running、端口通,但推理不回 静默故障(进程卡死) 看虚推是否开启 / GET /status 是否 abnormal

常见报错清单(官方原文 → 现象映射)

⚠️ 官方没有一份"本课专属的报错码表" —— 下面每一条都是官方原文 / 运维技巧里给的现象或说明, 按"现象 → 官方说明 → 先查什么"整理,不是编造的错误码。

现象 / 报错 官方说明 先查什么
推理接口返回 {"detail":"Service is not available"} 服务未就绪;"多为 P/D 或 Coordinator 尚未完全就绪" 等待重试 + bash show_log.sh 看各 Pod 日志
Pod Running 但推理无响应 可能是静默故障(官方:"部分进程卡死,服务看似无问题") 虚推是否满足启用条件;GET /status 是否 abnormal
配了虚推却不生效 官方:虚推仅允许在 ERROR 日志级别下开启 echo $ASCEND_GLOBAL_LOG_LEVEL 应为 3
虚推被自动关闭 官方启用条件不满足即自动关闭(非 vLLM / 非 ERROR / HDK 不支持 AI Cube Usage / 非 DP rank 0) 逐条对第五段的 6 个启用条件
npu-smi info watch -s u 不支持 官方:HDK 不支持该指标时虚推自动关闭 确认 HDK ≥ 26.0.RC1
权重加载报 timeout(超过约 10 分钟) 官方:通常不影响程序运行;以所用镜像 / 引擎版本说明为准 先看服务是否最终就绪,别急着推倒重来
删掉一个 Pod 却没触发实例重调度 官方:实例重调度依赖 MindCluster;P/D 实例含多个 Pod 时,直接删除其中一个 Pod 不会触发实例重调度 走完整的实例重调度,而不是手删 Pod
部署失败,想重来 官方:可先按终止服务小节的命令卸载,排查并修改配置后重新部署 bash delete.sh <namespace>
Pod 起不来 / 找不到镜像或权重 官方:确保 image_name 在集群内可正常拉取、weight_mount_path 在宿主机上存在 查镜像仓库可达性与挂载路径
开了主备倒换但起不来 官方:依赖 ETCD v3.6、至少 3 个副本 查 etcd 部署与版本(4.8 第 ① 条)
主备切了但没生效 / 只支持特定场景 官方(22RC1):该特性只支持在大规模专家并行场景下使用 确认你的场景是否在支持范围内

⭐ 检索技巧(E1 讲过,这里再用一次):去掉具体化信息。 不要搜"我们的服务莫名不动了",要搜报错原文里的稳定特征词 (Service is not available、abnormal、npu_usage_threshold 等)。

三层判断法(本课的框架)

归纳(结合 D3/D4 的成果):

① 是"没就绪"还是"静默故障"还是"坏了"?
     没就绪   → 等待 + 看启动日志
     静默故障 → 看虚推 / GET /status(本课新增)
     坏了     → 往下走第 ② 步

② 是"哪个角色"的问题?(D3)
     Coordinator / Controller / EngineServer / NodeManager / Deployer

③ 是"算的环节"还是"搬的环节"?(D4)
     算的 → 回 D2 / C 层
     搬的 → KV 传输 / KV Cache Store / 池化

⭐ 这个三层法,是把 D2–D5 串起来用的方法 —— 本课是它最上层的那一问(就绪 / 静默故障 / 坏了)。


第九段 · 小结与下一课

三句话带走

  1. 官方全量配置示例已默认开启六项能力:主备倒换、异常实例重启、服务限流、 虚推健康检查、KV Cache 亲和调度、KV 池化。 你要学的不是"怎么开",而是"它是什么、现象长什么样、什么时候该调"。
  2. 最该记住的一个概念是"静默故障"(官方原文): "部分进程卡死,服务看似无问题,但无法正常推理" —— 虚推健康检查就是为它准备的;而它恰好能骗过"端口通不通"这一层。
  3. 官方给的万能报错映射:接口返回 {"detail":"Service is not available"} → "多为 P/D 或 Coordinator 尚未完全就绪" → 等待重试 + 查看各 Pod 日志。

D 层到这里收官

回头看这一层讲了什么:

D1  L3 服务层在干什么、MindIE 是什么、官方推荐哪条路
D2  把服务跑起来(vLLM Ascend 三步走 + 三重验证)
D3  服务由哪些角色组成(Motor 五组件 + 端口规划)
D4  为什么要拆 P 和 D(计算密集 vs 访存密集 + KV 传输的代价)
D5  起来之后怎么活下去(可用性 / 健康 / 保护 / 调优)

D 层的一句话总结:

L1/L2 解决"一个请求怎么算对",L3 解决"一万个请求怎么算得完"。 这一层的所有设计(拆 P/D、限流、健康检查、KV 复用), 都是在"资源有限"这个前提下做的取舍。

本课在体系里的位置

─── L0 硬件与环境(A 层,已完成)─── A0 / A1 / A2 / A3
─── L1 基础软件(B 层,已完成)─── B1 / B2 / B3 / B4 / B5
─── L2 框架(C 层,已完成)─── C1 / C2 / C3
─── L3 服务(D 层,本课收官)───
D1 L3 服务层        ✅
D2 vLLM Ascend      ✅
D3 MindIE Motor     ✅
D4 PD 分离与混部     ✅
D5 可用性、健康与调优 ★ 本课
─── 排障(E 层)─── E1

本课留下的"钩子"

钩子 在哪一课填
服务侧的日志在哪、怎么收集与定位 E 层(E1 讲了日志三处)
KV 池化 / KV 亲和的完整配置 官方《KV 池化部署指南》《KV Cache 亲和性调度》
量化(msModelSlim)——A0 地图里属于 L4 应用层 D 层之后
950 系列服务器的预检查(官方文档有专门一节) 官方《PD 分离服务部署指导》

课后自测(3 题)

  1. "静默故障"是什么样?为什么它特别危险?虚推健康检查用哪两种方式探测?
  2. 虚推有一个容易踩的限制条件——调日志级别会让你悄悄失去它。是什么条件?
  3. 接口返回 {"detail":"Service is not available"},官方说多半是什么原因?你该做什么?

附录 A · 本课引用的官方出处

内容 出处
「全量示例已默认开启主备倒换、异常实例重启、服务限流、虚推、KV 亲和性调度、KV 池化」 官方 MindIE《基于 K8s 多容器 PD 分离服务部署 · 特性配置指导》
zh/mindie/310/mindiemotor/motordev/docs/zh/user_guide/deployment/k8s/pd_disaggregation_deployment.md
主备倒换的原理、开启配置、关闭方式、「须提前部署 etcd(建议 3 副本)」 同上
异常实例重启的原理、「默认开启,无需额外操作」「无需关闭」 同上
服务限流的原理、rate_limit_config 三个字段与「60 秒内最多处理 10000 条请求」 同上
虚推健康检查的定义(含"静默故障表现为:部分进程卡死,服务看似无问题,但无法正常推理")、原理、配置、「仅允许在 ERROR 日志级别下开启」ASCEND_GLOBAL_LOG_LEVEL=3 与自动关闭并打印 warning 同上
KV Cache 亲和调度的目的、原理(依赖 Mooncake Conductor)、配置要点、「需要确保镜像中已安装 KV Conductor 组件」 同上
KV 池化的目的、原理(MultiConnector、P 推入 / D 拉取)、关闭方式、指向《KV 池化部署指南》 同上
运维技巧 · 服务未就绪:{"detail":"Service is not available"} →「多为 P/D 或 Coordinator 尚未完全就绪;等待后重试,并查看各 Pod 日志」 同上(附录 · 运维技巧)
主备倒换的限制与约束(主备不支持同节点、依赖 ETCD 3 副本、ETCD v3.6、明文传输风险) 官方 MindIE《集群管理组件 · Controller 主备倒换 · 使用样例》(22RC1)
https://www.hiascend.com/document/detail/zh/mindie/22RC1/mindieservice/servicedev/mindie_service0371.html

⚠️ 数据纪律提示: ① 上表主备倒换的限制条款出自 22RC1 版本文档(官方 3.1.0 文档指向该特性说明)—— 不同版本的具体约束可能不同,以对应版本文档为准; ② KV 池化的完整参数本课未搬运(官方明说"参数较多"),以官方指南为准; ③ 日志路径与收集方式本课未给出,以官方文档与 E1 为准; ④ 标注「归纳」的内容(六项能力分类、三层判断法、日志归属表)非官方口径。


附录 B · 本课出现的配置项与名词详解

配置块速查

配置块 位置 作用
standby_config.enable_master_standby motor_controller_config / motor_coordinator_config 主备倒换开关
rate_limit_config motor_coordinator_config 服务限流(enable_rate_limit / max_requests / window_size)
health_check_config motor_engine_prefill_config(P 与 D 各自) 虚推健康检查(enable_virtual_inference / npu_usage_threshold)
scheduler_config.scheduler_type motor_coordinator_config 设为 "kv_cache_affinity" 开启 KV 亲和调度
kv_conductor_config 与 motor_engine_prefill_config 同层级 KV Conductor 配置
kv_cache_pool_config 根节点 KV 池化(删除即关闭)

名词表

名词 一句话
主备倒换 多套 Controller/Coordinator 分布在不同服务器,主挂备接管
异常实例重启 实例异常退出时 Motor 自动重启(默认开启、无需关闭)
服务限流 Coordinator 限制单位时间最大请求数
虚推健康检查 小型推理请求 / 看 NPU 使用率,专治"静默故障"
静默故障 部分进程卡死,服务看似无问题,但无法正常推理
KV Cache 亲和调度 前缀相同的请求送到同一实例,复用 KV,省 Prefill
KV 池化 KV Cache 卸载到共享池,跨实例复用,降显存压力
Mooncake Conductor KV 亲和调度依赖的社区组件
MultiConnector KV 池化用到的连接器
etcd 主备倒换依赖的协调服务(官方:建议 3 副本)
ASCEND_GLOBAL_LOG_LEVEL=3 ERROR 级别;虚推只允许在此级别下开启(0=DEBUG/1=INFO/2=WARNING/3=ERROR)
AI Cube 利用率 虚推在业务繁忙时的探测判据(npu-smi info watch -s u 采集)
虚推启用条件 须同时满足 6 条(vLLM / 开关 / ERROR 级别 / 阈值 / /health 正常 / DP rank 0)

命令与现象

项 说明
{"detail":"Service is not available"} 推理接口返回此内容 → 官方:多为 P/D 或 Coordinator 尚未完全就绪
kill -2 <PID> 优雅停止(D2 讲过,相当于 Ctrl+C)
npu_usage_threshold 虚推判据之一:NPU 计算核心使用率阈值
kubectl get pods -n <namespace> -o wide 看 Pod 状态;官方:Running ≠ 业务就绪
GET /v1/readiness(及 Triton 版 GET /v2/health/ready) 官方就绪接口:200 = 已就绪,503 = 未就绪
npu-smi info watch -s u / -h 看 AI Cube 利用率 / 查是否支持该指标(虚推前置)
bash show_log.sh 官方日志采集入口,输出到 log_collect/log/
bash delete.sh <namespace> 官方终止 / 卸载服务
python3 deploy.py --config_dir ../infer_engines/vllm 官方拉起 PD 分离服务

附:D3 / D4 / D5 的分工

问题 在哪一课
Motor 五个子组件、部署形态、端口规划 D3
Prefill/Decode 的差别、PD 分离的动机与代价 D4
六项能力(主备倒换/异常重启/限流/虚推/亲和/池化)、就绪判断、静默故障 本课(D5)
日志收集与按层排错 E 层
选修 · 昇腾 AI 部署实操 本机读完 0/51
选修 C · 昇腾 AI 部署实操
从零把昇腾 AI 部署学一遍:先看懂分几层,再逐层装起来,最后出问题能自己定位到哪一层。不需要先有卡就能开始。
下一站 → D 层部署指南 · L3服务 (文章)
看完整学习路径(6 站 + 3 门选修) · 进度只存在你这台设备的浏览器里,不用登录
辽ICP备2026019944号-1