| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
update license Co-authored-by: y1lou<louyi6@huawei.com> # message auto-generated for no-merge-commit merge: !185 merge update_license into master update license Created-by: y1lou Commit-by: y1lou Merged-by: ascend-robot Description: ## **1. 合入背景** > 请描述为什么要做这个PR内的改动。\ > 如涉及,请关联前序PR或同特性/需求下的其他PR。\ > 如果是修复之前PR引入的问题,请关联引入问题的PR。\ > 请通过#ISSUE ID关联issue。\ > 注意: Fixes #ISSUE ID会自动关闭issue,如问题部分解决请不要使用Fixes,可以用Fix part of #ISSUE ID替代. ## **2. 修改内容** > 请<ins>**描述修改内容的具体实现**</ins>,涉及哪些组件之间进行交互,可以用1、2、3、...进行罗列。 > 如果是需求或者重构类的PR,需要<ins>**补充详细设计文档**</ins>(说明上下游组件关系、时序图、类图、DFX能力等内容)。 ## **3. 资料变更** > 请确认<ins>**是否涉及资料变更**</ins>。\ > 如涉及,需要在PR中体现,并简要说明修改内容。\ > 如不涉及,需填写“不涉及”。 ## **4. 接口变更** > 请确认<ins>**是否涉及跨代码仓或者客户面可见的接口变更**</ins>。\ > 如涉及,需详细说明接口以及对应的变更内容,同时需要在资料中体现。\ > 如不涉及,需填写“不涉及”。 ## **5. 测试结果** > 需体现<ins>**测试场景,测试方法以及测试结果**</ins>。\ > 测试用例设计时需考虑硬件、部署方式、功能、性能、精度、显存等维度。 ## **6. CheckList** > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] [ ] 代码注释完备 [ ] 正确记录维测日志 [ ] 是否有UT用例 [ ] 若涉及多线程场景,考虑了并发场景,不存在死锁问题 See merge request: Ascend/MindIE-pyMotor!185 | 8 个月前 | |
[bugfix] 修复主备coordinator倒换快恢超时 Co-authored-by: mindie_yangan<yangan7@h-partners.com> # message auto-generated for no-merge-commit merge: !900 merge coordha30s into master [bugfix] 修复主备coordinator倒换快恢超时 Created-by: mindie_yangan Commit-by: mindie_yangan Merged-by: towncharlie Description: ## **1. 背景** Fixes #558 https://gitcode.com/Ascend/MindIE-Motor/issues/558 双 Coordinator + PD 分离部署。对当前主 Coordinator 的网卡注入 100% 丢包后,推理约 65 秒才恢复到 200,超过 30 秒快恢要求。同一服务反复验收时,有时 30 秒后 200、有时超时。 ## **2. 分析** ### 2.1 复现方法 1. 双 Coordinator + PD 分离拉起,等引擎加载完成、推理已能返回 200。稳态要求:主 Coordinator 1/1,备 Coordinator 0/1。当前 master 的安装包需带 libmindie_workload_shm.so,否则 Coordinator Mgmt 起不来,后面步骤做不了。 2. 在当前主 Coordinator 的 netns 注入丢包。容器内无 tc 或无 NET_ADMIN 时,到 Pod 所在节点对 sandbox/pause PID 执行 nsenter -t $PID -n: tc qdisc add dev eth0 root netem loss 100% 3. 从注入时刻起算,30 秒后发起一次推理,返回 200 即达标。空 503 不要直接喂给 jq,否则看不到真实返回。 4. 清理:tc qdisc del dev eth0 root netem。 5. 连续验证第二轮时,要对当时的主 Coordinator 所在节点注入,并先清掉上一轮残留的 tc。 ### 2.2 现象分析 改前配置 ttl=15。备升主本身约 15–20 秒(etcd 锁 TTL 15s)。其余时间有两段:Controller 把 P/D 实例 SET 到新主;以及推理 Service 仍把请求打到已被隔离、但还在端点里的旧主。65 秒按阶段拆开: | 阶段 | 耗时 | 说明 | | --- | --- | --- | | 注入 → 原主续约失败、让出锁 | ~15s | etcd 锁 TTL 15s | | 备抢锁升主 → 上报 Ready | ~5s | 符合预期 | | 升主 → Controller 把实例 SET 到新主 | 原约 45s | 管理面超时来源 | | 新主已 Ready → 推理仍超时 | 与上一行重叠 | 数据面:Service 仍打到隔离旧主 | Controller 侧四处串行等待: 1. Controller 只靠 /readiness 心跳发现倒换,10s 周期,且要等下一次心跳成功才入队 SET。新主升主的同一秒已上报 0xFC001008 并拿到 200,但 Controller 当时只记录告警、不推实例。 2. /instances/refresh 的 Keep-Alive 连接钉在已被隔离的原主 Pod 上,倒换后第一次 POST 要先等 TCP 超时才失败。 3. SET 失败后不再重新入队,只能等 300s 周期同步兜底。 4. SET 打的是 coordinator-mgmt Service。原主被隔离、或 503 后被摘除端点时,新主又因实例池为空进不了 Ready,Service 此刻没有任何可用端点,SET 全部超时,新主一次 Refresh 都收不到。 只修上面四条之后,管理面能很快 SET 成功,但同一服务反复验收仍会抖: 5. 推理走 mindie-motor-coordinator-infer。readiness 是容器内 exec,看不到 eth0 出方向 100% 丢包。旧主在丢掉 etcd 锁之前一直 Ready;让锁后还要等探针失败才摘端点。这段时间 kube-proxy 仍可能把请求打到黑洞 Pod。sleep 30s 正好卡在摘端点边界上,所以有时过、有时不过。 ### 2.3 结论与根因 1. 升主事件没有被用来触发推送。0xFC001008 已经送达 Controller,但只落到告警,没有驱动 SET。 2. SET 的目标地址不对。倒换瞬间 Service 无可用端点,此刻只有 Coordinator Pod IP 可达。 3. SET 失败即丢弃,没有重试,退化成 300s 周期同步。 4. Keep-Alive 连接不失效,倒换后仍复用指向原主的连接。 5. 隔离旧主不离开推理 Service。readiness 只看是不是 master,续约失败到让锁、再到摘端点,旧主一直在 selector 里。这是验收抖动的直接原因。 6. 配置 ttl=15 / interval=5 时,旧主 503 之后、备还没拿到锁之前,推理 Service 可能没有 Ready 端点。30s 验收会空窗。 补充「为什么以前能过 30 秒」:以前走的是原主没有丢掉 etcd 锁、原地恢复 worker,备始终抢不到锁,根本走不到 Controller SET 和 Service 摘端点。tc loss 100% 会让原主续约失败并让出锁。相关背景见 #558。 ### 2.4 解决方案 逐条对应 2.3: 1. 对根因 1:/observability/add_alarm 收到既有的 0xFC001008 即调用 notify_coordinator_failover(),立即入队全量 SET,不再等心跳。 2. 对根因 2:告警对端 IP 作为 refresh override;同时按本 namespace 的 Coordinator pod IP 广播 SET(备即使 0/1 也能收到 mgmt 上的 Refresh)。没有 POD_NAMESPACE 时不扫全集群。pod IP 全部失败时再补一次 host=None。 3. 对根因 3:_resync_after_hb_loss 期间 SET 失败按 1s 重试直到成功。 4. 对根因 4:心跳失败立即 reset_refresh_client(),丢掉钉在原主上的 Keep-Alive。 5. 兜底:_HB_LOSS_SET_THRESHOLD=1,心跳侧首次失败即入队 SET。 6. 对根因 5:第一次续约失败写 ROLE_SHM_ISOLATED,readiness 立刻 503。真正丢锁后,K8s 里 os._exit(1),kubelet 摘掉旧主。备保持 0/1(和改前一样),只预热 InferenceWorkers,升主后才能 1/1。 7. 对根因 6:Daemon 运行时把 master_lock_ttl 压到不超过 8、master_standby_check_interval 压到不超过 2;config_sample.json 里 coordinator 样例同步为 8/2。clamp 留给旧配置兜底。 明确不在本 PR 范围: - 不改部署模板的 readiness/liveness 阈值。快速摘旧主靠 K8s 下丢锁退出,不靠改 probe 次数。 - 不加 sessionAffinity,不改推理 Service 的流量模型文档。 - /readiness 心跳仍是独立故障检测,不读 alarm。 - 稳态不把备做成 1/1。测试要求主 1/1、备 0/1。 ## **3. 修改内容** ### 3.1 修改清单 业务代码: - motor/common/standby/standby_manager.py - motor/config/coordinator.py - motor/controller/api_client/coordinator_api_client.py - motor/controller/api_server/controller_api.py - motor/controller/core/event_pusher.py - motor/controller/fault_tolerance/k8s/k8s_client.py - motor/coordinator/daemon/coordinator_daemon.py - motor/coordinator/domain/probe.py 样例: - examples/features/config_sample.json(仅 coordinator 的 ttl/interval;controller 样例仍是 15/5) DT: - tests/controller/api_client/test_coordinator_api_client.py - tests/coordinator/test_http_server.py - tests/coordinator/test_main.py ### 3.2 业务代码的修改 controller_api.py / event_pusher.py:0xFC001008 触发 notify_coordinator_failover,pin 对端 IP,入队全量 SET;心跳失败重置客户端并按 1s 重试 SET。 coordinator_api_client.py:SET/ADD 广播本 namespace 的 Coordinator pod IP;没有 namespace 不扫全集群;pod IP 全部失败时再补一次 host=None。 standby_manager.py / coordinator_daemon.py:续约第一次失败标 isolated;K8s 丢锁退出;非 K8s 保留进程。运行时 clamp ttl≤8、interval≤2。备上也拉起 InferenceWorkers,只用于升主后立刻能服务。 probe.py:isolated → 503;master 有实例 → 1/1;standby → 0/1(Coordinator is not master),与改前一致。 ### 3.3 DT 修改 - _on_become_standby:K8s 断言 os._exit(1),非 K8s 不退出。 - standby + 实例的 readiness 保持 503。 - SET 在无 namespace 时不扫 pod;pod IP 全失败后补一次 host=None。 ### 3.4 pre-commit 修改 无配置变更。 ## **4. 自验证** 自验证脚本(在当前主 Coordinator 所在节点执行;对 sandbox/pause PID 注入,不要用业务容器 PID。下面 Pod 名、脚本路径换成当时的实际值): bash # 换成当时的实际值 POD_NAME="<当前主 Coordinator Pod 名>" INFER_SH="<推理脚本路径>" # 1. Pod 名字 → sandbox PID POD_ID=$(crictl pods --name "$POD_NAME" -q) echo "POD_ID=$POD_ID" PID=$(crictl inspectp --output go-template --template '{{.info.pid}}' "$POD_ID") echo "PID=$PID" # 2. 注入:这个 Pod 网卡 100% 丢包 nsenter -t "$PID" -n tc qdisc add dev eth0 root netem loss 100% # 3. 从注入起等 30 秒,再发一条推理 sleep 30s bash "$INFER_SH" # 4. 恢复 sleep 30s nsenter -t "$PID" -n tc qdisc del dev eth0 root netem 自验证脚本运行结果:  See merge request: Ascend/MindIE-Motor!900 | 1 个月前 | |
[Feature] 推理大EP场景下支持DP域缩容运行 Co-authored-by: yilunh<hanyilun1@huawei.com> Co-authored-by: Jechin<yuzechen1@huawei.com> # message auto-generated for no-merge-commit merge: !964 merge scaledown into master [Feature] 推理大EP场景下支持DP域缩容运行 Created-by: yilunh Commit-by: yilunh;Jechin Merged-by: towncharlie Description: ## **1. 合入背景** MoE/EP 推理实例中部分 DP rank 因 NPU、网络或引擎故障失效时,现网主要走隔离实例后的引擎重拉起、Pod 重调度或 Scale P2D。单 rank 死亡也会扰动全部健康 Pod,恢复偏慢。 本 PR 在 **引擎 FT + external-lb + EPLB 冗余专家** 等条件满足时,由 Controller 编排 **DP 域缩容**:只移除权威故障原始 DP rank,存活 rank 重建通信域后继续服务,实际缩容可行性由引擎在 apply 后做最终可执行判断。 Fixes [#575](https://gitcode.com/Ascend/MindIE-Motor/issues/575) ## **2. 修改内容** 领域与策略: - motor/controller/fault_tolerance/dp_scale_down.py(新增) - motor/controller/fault_tolerance/serving_overlay.py(新增) - motor/controller/fault_tolerance/pod_lifecycle.py(新增) - motor/controller/fault_tolerance/strategy/dp_scale_down.py(新增) - motor/controller/fault_tolerance/strategy/fast_recovery.py - motor/controller/fault_tolerance/strategy/reconfiguration.py - motor/controller/fault_tolerance/strategy/engine_relaunch.py - motor/controller/fault_tolerance/strategy/strategy.py - motor/controller/fault_tolerance/fault_manager.py - motor/controller/fault_tolerance/fault_types.py - motor/controller/fault_tolerance/mixin/persistence.py 控制面衔接: - motor/controller/core/instance_manager.py - motor/controller/core/event_pusher.py - motor/controller/core/instance_assembler.py - motor/controller/api_server/controller_api.py - motor/controller/api_client/node_manager_api_client.py - motor/controller/controller.py NodeManager: - motor/node_manager/api_server/node_manager_api.py - motor/node_manager/core/engine_ft_manager.py(新增) - motor/node_manager/core/fault_reporter.py - motor/node_manager/core/heartbeat_manager.py - motor/node_manager/core/register_manager.py - motor/node_manager/core/daemon.py 公共与配置: - motor/common/http/engine_ft_client.py - motor/common/resources/instance.py - motor/common/resources/http_msg_spec.py - motor/common/constants.py - motor/config/controller.py - motor/config/node_manager.py - examples/features/config_sample.json - docs/zh/user_guide/configuration/config_reference.md - .agents/skills/motor-dev/references/controller.md - .agents/skills/motor-dev/references/nodeman.md **FaultManager**:当前仅占位,is_applicable() 为 false 时,有 DEAD 或可映射硬件候选则进 DpScaleDownStrategy;仅 UNHEALTHY 且无权威候选时不猜 rank、不启动 30 秒 apply-ready 计时器,等待后续 DEAD / 硬件候选或故障清除事件;其他不能缩容的故障走原 fallback。硬件 L4–L6 可映射时推迟 separate_instance。失败绑定进入缩容前的 fallback_strategy,不重复本轮缩容。抢占时同时等 is_finished() 与执行器 Future。 异步策略完成时,FaultManager 先结算完成结果并清理上一轮软件故障,再构建下一轮恢复计划,避免残留 survivor UNHEALTHY 把已提交的 SCALED_DOWN_RUNNING 覆盖回 WAITING_ENGINE_FAULT。 **DpScaleDownStrategy**:门禁 → 按完整 NM 拓扑分组 → guard(request_id, lease) → 等到 survivor UNHEALTHY 且无 ft_state(引擎 id 必须等于全局 DP rank)→ ServingOverlay.withdraw → 一次 scale_down apply → 轮询至全部 HEALTHY → finalize(commit) → 可选 stop_recyclable_pods → publish。finally 未 commit 则 finalize(abort);NM 拒绝 stale request_id。 **ServingOverlay / EventPusher / InstanceManager**:权威拓扑不变;Coordinator 只看到过滤后的 endpoint。缩容事务中抑制 partial-loss shutdown;SCALED_DOWN_RUNNING 心跳允许且仅允许 dead_committed 缺失。 **FtRuntimeStore**:进程内原子状态;etcd 开启时只持久 phase/original_dp_ranks/dead_committed/fallback_strategy。中断事务恢复为 RECONFIGURING,不重放 apply。连续缩容由累计 dead_committed 表达,不设置人工轮数上限;旧快照中的 generation 被忽略。实例删除时同步删除对应 runtime;同 Job 的最新替代实例 Ready 后清理旧 instance id 的 runtime,删除结果同步持久化。 **NodeManager**:enable_dp_scale_down_proxy 由 Controller 的 enable_fault_tolerance && enable_dp_scale_down 派生,客户不单独配。四条 FT 路由;guard/finalize 带事务 id。commit 后 retired ranks 从心跳、EngineFtManager 轮询和进程死亡上报中过滤。EngineFtManager 仅在引擎 readiness 成功后启动,运行期首次 status 请求失败即上报 DEAD;遗留 max_poll_failures 当前不参与判定。 **FtGate**:校验引擎 FT、external-lb、scale_down_supported、auto recovery 冲突、enable_eplb 与 eplb_config.num_redundant_experts > 0。不再校验 additional_config.enable_fused_mc2,也不引入私有「可删 DP 预算」;apply 后由引擎对算子兼容性和真实专家槽位做最终判断。 **查询**:GET /controller/fault_tolerance/status;开关关闭返回 DISABLED。接口只返回当前生命周期内的 runtime:活动重配置状态保持可观察,已删除或已被 Ready 新实例替代的旧实例状态不再残留。 ## **3. 资料变更** - 更新 examples/features/config_sample.json 与配置参考,说明缩容/扩容控制项统一位于 Controller 的 fault_tolerance_config。 - 更新 Controller、NodeManager 开发参考,记录 FT runtime、服务视图投影、NM proxy、guard/finalize、retired endpoint 过滤及测试入口。 - RFC 补充状态机、事务一致性窗口、失败语义、REST 状态示例和 E2E 验收矩阵。 ## **4. 接口变更** 新增客户面可见配置开关 json "fault_tolerance_config": { "enable_fault_tolerance": true, "enable_dp_scale_down": false, "enable_dp_scale_up": false, "dp_scale_down_config": { "request_timeout_sec": 5.0, "poll_interval_sec": 1.0, "execution_deadline_sec": 30.0 } } NodeManager 的代理开关由上述两项派生,不必在 NM 配置里再写一份。 enable_dp_scale_up 是暂定内部名称。本 PR 中它只控制“缩容成功后是否允许 stop 已收空 Pod、交给集群补充资源”,不代表 Motor 已实现 DP rank 扩容事务。 | 类型 | 变化 | 开关关闭时行为 | |---|---|---| | Controller REST | 新增 GET /controller/fault_tolerance/status[?instance_id=] | 返回 phase=DISABLED,不进入缩容编排 | | NodeManager REST | 新增 POST /node-manager/fault-tolerance/status | proxy 未派生启用时返回 404 | | NodeManager REST | 新增 POST /node-manager/fault-tolerance/apply | proxy 未派生启用时返回 404 | | NodeManager REST | 新增 POST /node-manager/fault-tolerance/guard | proxy 未派生启用时返回 404,不冻结 suicide | | NodeManager REST | 新增 POST /node-manager/fault-tolerance/finalize | proxy 未派生启用时返回 404,不维护 retired endpoint | | NodeManager 注册 | 注册信息携带 ft_capability,包括引擎是否支持 scale_down 及静态门禁能力 | 不驱动缩容逻辑 | | 实例组装 | 同一实例各 Pod 的 FT capability 必须一致;缺失或不一致时失败封闭 | 不影响未开启缩容的既有服务路径 | | 内部配置 | enable_dp_scale_down_proxy = enable_fault_tolerance && enable_dp_scale_down | 客户无需单独配置;结果为 false | ## **5. 测试结果** Kill worker_dp1  Curl四个dp的status,由healthy变unhealthy  dp3同步hccl状态后也变成unhealthy,检测到dead+unhealthy之后触发dp缩容,NM下发apply:  缩容结束,健康rank的status状态变为healthy,   推理恢复正常  精度正常  缩容状态查询,由SCALING_DOWN更新为SCALED_DOWN_RUNNING  ## **6. CheckList** > PR提交人对以下CheckList自检项进行全量自检,自检通过或不涉及,均修改 [ ] 为 [x] [ ] 代码注释完备 [ ] 正确记录维测日志 [ ] 是否有UT用例 [ ] 若涉及多线程场景,考虑了并发场景,不存在死锁问题 See merge request: Ascend/MindIE-Motor!964 | 1 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 8 个月前 | ||
| 1 个月前 | ||
| 1 个月前 |