diff --git a/src/docs/advisor-demo-cases.md b/src/docs/advisor-demo-cases.md new file mode 100644 index 00000000..7195a49e --- /dev/null +++ b/src/docs/advisor-demo-cases.md @@ -0,0 +1,190 @@ +# Scheduler-Advisor 手工演示用例手册 + +备选演示场景,全部在 t1/t2/t3 测试集群实测通过(2026-10-19/20,分支 +feature/scheduler-advisor,advisor 提交 1691e49a)。按演示时长和戏剧效果排 +序:用例 1 最稳(确定性回显、零外部依赖),用例 2 最出彩(真 LLM 抓跨字段 +不一致),用例 3 最直观(节点故障)。 + +## 前置条件(演示前检查一次) + +```bash +# 1. 六个 daemon 全活:apiserver / controller / scheduler / xcecd(t1,t2,t3) +ps aux | grep -E "[x]ce_apiserver|[x]ce_controller|[x]ce_scheduler" | wc -l # ≥3 +ssh t2 'ps aux | grep [x]cecd | wc -l' # ≥1(t3 同理;t1 本机直接看) + +# 2. 三台主机 OK +KEY=$(cat /tmp/advisor_apikey_v2) +curl -s -H "Authorization: Bearer $KEY" http://172.31.1.30:8080/xce/v1/hosts \ + | python3 -c "import sys,json;[print(r['Data']['host_name'],r['Data']['host_status']) for r in json.load(sys.stdin)['data']['rows']]" +# 期望:t1 OK / t2 OK / t3 OK + +# 3. advisor 存活且在扫描(60s 一轮) +ps aux | grep [x]ce-advisor | wc -l # ≥1 +tail -2 /opt/xce/logs/advisor.log # 期望 "scan clean (0 pend, 0 run, 3 nodes)" + +# 4. LLM 路由可用(用例 2 需要;不通则 advisor 自动降级 echo,演示仍可做但亮点变少) +curl -s -m 10 http://127.0.0.1:6789/v1/models -H "Authorization: Bearer sk-litellm-router" | head -c 120 + +# 5. API key 是否有效(apiserver 重启过就失效,见"坑"一节) +curl -s -H "Authorization: Bearer $KEY" "http://172.31.1.30:8080/xce/v1/jobs?limit=1" | head -c 80 +``` + +advisor 启动命令(若未运行): + +```bash +env XCE_API_URL=http://172.31.1.30:8080 \ + XCE_API_KEY=$(cat /tmp/advisor_apikey_v2) \ + ADVISOR_LLM_BASE_URL=http://127.0.0.1:6789/v1 \ + ADVISOR_LLM_API_KEY=sk-litellm-router \ + ADVISOR_LLM_MODEL=glm-5-3-flash \ + ADVISOR_INTERVAL=60s \ + ADVISOR_LOG=/opt/xce/logs/advisor-decisions.jsonl \ + nohup setsid /tmp/xce-advisor-new run >> /opt/xce/logs/advisor.log 2>&1 & +``` + +--- + +## 用例 1:PEND 作业卡死诊断(最稳,5-8 分钟) + +**故事**:一个作业因为资源需求永远无法满足而卡在队列里,无人察觉。advisor +自动发现、诊断、给出建议。 + +**步骤**: + +```bash +# 1. 提交一个"不可能满足"的作业(r1m>9999 可解析但无节点能满足) +export PATH=/opt/xce/bin:$PATH +xce login -u admin -p admin --url http://172.31.1.30:8080 +xce jobs submit -J demo-pend -q normal -R "select[r1m > 9999]" "sleep 300" +# 输出:Job <...> is submitted to default queue + +# 2. (可选但推荐)开一个 SSE 监听窗,现场看到 advisor.finding 事件飞出来 +KEY=$(cat /tmp/advisor_apikey_v2) +curl -s -N -H "Authorization: Bearer $KEY" http://172.31.1.30:8080/xce/v1/events + +# 3. 等待:提交后 5 分钟(stall 阈值)+ 最多 1 分钟(扫描间隔) +# 即最迟 ~6 分钟后看到事件和决策 +``` + +**预期输出**(advisor 日志 `/opt/xce/logs/advisor.log`): + +``` +advisor: pend_stall [pending=1 stalled=1] -> 1 finding(s) (model=glm-5-3-flash, ~20s, degraded=false) +``` + +SSE 窗口出现 `data: {"type":"advisor.finding","job_status":"pend_stall",...}`; +MCP 工具 `scheduler_advisor_findings` 同时能查到同一条记录(见用例 4)。 + +**卖点**:从作业卡死到诊断推送 ≤6 分钟,全程无人操作、只读、零侵入。 + +**去重语义现场演示(加分项)**:什么都不做,advisor 不会重复刷屏(同一情形 +永不重报);此时**再提交第二个**卡死作业(`-n 64`): + +```bash +xce jobs submit -J demo-pend-2 -q normal -n 64 "sleep 300" +``` + +下一个扫描轮(≤1 分钟)立即出**新**决策(变化即触发)——演示"恶化会被 +即时上报,而不是被冷却时间捂住"。 + +**清理**: + +```bash +xce jobs list # 拿到 JOBID +xce jobs kill [JOBID2] +# 等 1-2 分钟,advisor 日志回到 "scan clean" +``` + +--- + +## 用例 2:真 LLM 抓跨字段不一致(最出彩,需 LLM 路由) + +与用例 1 同一操作,但重点展示 LLM 的增值:glm-5-3-flash 在同一份快照上 +输出了 echo 规则给不出的**第二条** finding——"cluster 报 2 个 pending, +但队列 normal 报 0 pending 0 running,记账不一致"。这是真实观测(两次 +独立运行都出现),evidence 全部逐字可验、unverified=false。 + +**讲法**:echo 是基线(兜底、零成本),LLM 是增量(跨字段关联);防火墙 +保证 LLM 说的话每个标识符都能在快照里找到原文,编造就降级标记。 + +**风险预案**:glm 路由偶发超时(30s 超时后自动降级 echo,决策标记 +degraded=true)——现场反而是卖点:"外部模型挂了,advisor 没挂"。 + +--- + +## 用例 3:节点故障检测(最快出活,2-3 分钟) + +**故事**:一台节点挂了/被维护关了,advisor 立即感知容量损失。 + +```bash +# 1. 关闭 t3(模拟节点故障) +export PATH=/opt/xce/bin:$PATH +xce hosts close t3 +# xce hosts list 显示 t3 CLOSED_BY_ADMIN + +# 2. 等 ≤1 个扫描周期(60s),advisor 日志: +# advisor: worker_health [t3:down] -> 1 finding(s) (model=glm-5-3-flash, ~12s, degraded=false) +# SSE advisor.finding: +# "Node t3 is down while t1 and t2 are idle; cluster capacity is +# reduced to 2 of 3 hosts..." +# 建议语提示确认是否计划内维护。 + +# 3. 恢复 +xce hosts open t3 +``` + +**实测坑(演示前必读)**:**重复故障会被去重吞掉**。当前实现的 dedup key +在节点恢复(全健康)时**不清除**——同一节点第二次 close 不会再报(实测 +01:20 复测确认)。两个选择: +- 演示只做**一次** close(安全); +- 或者先修这个缺口再演示:`fire()` 之后任何一轮全健康时应把该场景的 + lastKey 清掉(一行改动 + 测试),修复后"每次新故障都报"。 + +**清理**:`xce hosts open t3`,等日志回 scan clean。 + +--- + +## 用例 4:MCP 工具查询(收尾,1 分钟,零风险) + +不需要制造任何异常,直接展示决策日志可查(适合给领导看"可审计"): + +```bash +cd /tmp && env XCE_API_URL=http://172.31.1.30:8080 \ + XCE_API_KEY=$(cat /tmp/advisor_apikey_v2) \ + ADVISOR_LOG=/opt/xce/logs/advisor-decisions.jsonl \ + /tmp/xce-mcp-server-new <<'EOF' +{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"demo","version":"1.0"}}} +{"jsonrpc":"2.0","id":2,"method":"notifications/initialized"} +{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"scheduler_advisor_findings","arguments":{"tail":5}}} +EOF +``` + +在 Claude Code 里接上 mcp-server 后就是自然语言:"advisor 最近发现了什么?" +每条记录含 ts/scenario/provider/model/延迟/证据,与决策日志一一对应—— +"当时它看到了什么、说了什么"可完整回放。 + +--- + +## 已知坑与预案(演示前一天过一遍) + +| 坑 | 影响 | 预案 | +|---|---|---| +| **apiserver 重启使所有 API key 失效**(key 是纯内存 map,无持久化) | 所有 curl/xce 401 | 重新发:logon 拿 admin token → `POST /xce/v1/apikeys`(role_name=advisor_agent,username=advisor-svc)→ 存回 `/tmp/advisor_apikey_v2` → **重启 advisor** | +| glm 路由超时(偶发) | 用例 2 降级为 echo(degraded=true) | 顺势讲兜底设计;或演示前 `curl /v1/models` 预检 | +| SSE 监听用 `curl -m 180` 会在 5min 阈值前断 | 以为推送没到 | 监听窗口用 `-m 600` 以上,或用 MCP 工具事后查 | +| stall 阈值 5 分钟 | 用例 1 有 5-6 分钟干等 | 先讲架构图/MCP 工具填这段时间;或把演示作业提前 5 分钟提交 | +| 重复节点故障被 dedup 吞 | 用例 3 二连击失败 | 只关一次;或先修 lastKey 清除缺口 | +| advisor 进程死了 | 一切不输出 | 用前置检查第 3 步确认;重启命令见上 | + +## 演示后清场清单 + +```bash +# 1. kill 所有演示作业(确认 EXIT) +export PATH=/opt/xce/bin:$PATH && xce jobs list +# 2. 确认 t1/t2/t3 全 OK +xce hosts list +# 3. advisor 日志回到 "scan clean (0 pend, 0 run, 3 nodes)" +tail -2 /opt/xce/logs/advisor.log +# 4. (可选)归档本次演示的决策记录 +cp /opt/xce/logs/advisor-decisions.jsonl /tmp/demo-decisions-$(date +%Y%m%d-%H%M).jsonl +```