docs: external-resources (license + elim) user manual
Full user manual for the external-license-resources feature set (E2 Phases 1-3 + elim collector): concept/architecture (two collection legs, EXTERNAL admission formula total >= uncomit + wanted and its cross-job accounting split), cluster-side declaration (resources.yaml location: [external], flag semantics), config build/push/dump with the restart constraints, xceesd deployment (esd.yaml schema, CLI, runtime behavior incl. bug-1978 rejoin semantics), collector script contract, elim per-host collector (registry, interval gating, fail-to-zero semantics), limits.yaml per-project/per-queue quotas (vres names, LIMIT_GLOBAL vs NO_RESOURCE), job submission (rusage[] bracket rule, per-type semantics), operations (extres status, definition/distribution lists, debounced LAST_UPDATED), troubleshooting runbook, and a tested E2E recipe set (fake_lic.sh live-pid marker pool + licjob.sh checkout wrapper, global-pool / elim / per-project scenarios). All CLI flags, YAML schemas, output formats and commands verified against the live t1/t2/t3 cluster and source (cli.py, esd_config.c, elim.c, resource.c, xcealloc.c); known limitations listed explicitly (single daemon, unconsumed esd per-source interval, etc.). Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
0dc2bd2145
commit
0b47076d05
1 changed files with 864 additions and 0 deletions
864
src/docs/external-resources-user-manual.md
Normal file
864
src/docs/external-resources-user-manual.md
Normal file
|
|
@ -0,0 +1,864 @@
|
|||
# 外部资源(License + elim)用户手册
|
||||
|
||||
> 适用版本:working 分支(含 E2 Phase 1-3 与 elim 采集器,2026-10-28)。
|
||||
> 目标读者:需要接入外部 license 池或自定义主机资源,并对其做调度与测试的
|
||||
> 集群管理员和测试工程师。
|
||||
> 配套设计文档:`.kiro/specs/external-license-resources/design.md`。
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [概念与架构](#1-概念与架构)
|
||||
2. [集群侧资源声明](#2-集群侧资源声明)
|
||||
3. [配置构建与下发](#3-配置构建与下发)
|
||||
4. [全局腿:xceesd 部署](#4-全局腿xceesd-部署)
|
||||
5. [采集脚本契约](#5-采集脚本契约)
|
||||
6. [主机腿:elim 采集器](#6-主机腿elim-采集器)
|
||||
7. [策略层:limits 配额](#7-策略层limits-配额)
|
||||
8. [作业提交](#8-作业提交)
|
||||
9. [运维观测](#9-运维观测)
|
||||
10. [故障处理](#10-故障处理)
|
||||
11. [测试指南(E2E 配方)](#11-测试指南e2e-配方)
|
||||
12. [已知限制](#12-已知限制)
|
||||
|
||||
---
|
||||
|
||||
## 1. 概念与架构
|
||||
|
||||
### 1.1 两条腿
|
||||
|
||||
外部资源有两条独立的采集路径,共享同一套资源模型和记账规则:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────┐
|
||||
│ 调度器(准入判定) │
|
||||
│ EXTERNAL: total ≥ uncomit + wanted │
|
||||
│ 其他: total ≥ inuse + uncomit + wanted │
|
||||
└────────────┬───────────────────────────────────┘
|
||||
│ RESVALS_DELTA
|
||||
│ (host=="" → sharedInst 全局池)
|
||||
┌───────────────┴───────────────┐
|
||||
│ │
|
||||
┌──────────▼──────────┐ ┌──────────▼──────────┐
|
||||
│ 全局腿(license 池) │ │ 主机腿(elim 指标) │
|
||||
│ xceesd daemon │ │ xcecd -c external_ │
|
||||
│ controller 角色扩展 │ │ resources │
|
||||
│ (extres) │ │ worker resource_sync│
|
||||
└──────────┬──────────┘ └──────────┬──────────┘
|
||||
│ 脚本采集 │ 每主机脚本采集
|
||||
▼ ▼
|
||||
license 服务器/任何来源 本机 GPU/任何本机量
|
||||
```
|
||||
|
||||
- **全局腿**:`xceesd` 是一个独立 daemon,跑在一台机器上,周期执行若干采集
|
||||
脚本,把**集群级 free 值**(如剩余 license 数)推给 controller。它以
|
||||
`extres` 角色 join,推送落点是无 host 的共享实例(`sharedInst`),也就是
|
||||
"一个资源、一个全局池"。
|
||||
- **主机腿**:`xcecd`(worker 节点上的 daemon)支持
|
||||
`external_resources` 配置节,在每个主机本地执行脚本,把结果注册为自定义
|
||||
load index,走 worker 既有的 15 秒 load-index 上报链,落点是**每台主机各自
|
||||
的资源值**("一个资源、每主机一个池")。
|
||||
|
||||
同一个资源名(如 `extlic`)只能选一条腿——声明位置(`resourcemap` 的
|
||||
`location`)决定它落在哪条腿上。
|
||||
|
||||
### 1.2 EXTERNAL 语义与准入公式
|
||||
|
||||
带 `location: [external]` 声明的资源打上 `EXTERNAL` flag(0x10)。它与普通
|
||||
动态资源的关键区别在**记账规则**:
|
||||
|
||||
- 普通资源(含 elim 落地的动态资源):调度器按
|
||||
`total ≥ inuse + uncomit + wanted` 判准入——`inuse` 从节点上报值反推。
|
||||
- EXTERNAL 资源:**跳过 inuse**,只判 `total ≥ uncomit + wanted`。
|
||||
|
||||
原因:xceesd 推上来的已经是 license 服务器扣减后的 **free 值**(还剩多少
|
||||
可用),不是 total。作业占用的部分在 license 服务器侧已经体现为 free 值
|
||||
下降,调度器再算一遍 inuse 会双扣。脚本返回 free 值是该模型的核心约定。
|
||||
|
||||
实现位置:`src/scheduler/src/resource.c` `unsatisfy_()`(EXTERNAL 分支只做
|
||||
`total ≥ uncomit + wanted`);标记:`r->flags & XCE_RESF_EXTERNAL`。
|
||||
|
||||
**跨作业记账分工**(重要):EXTERNAL 池的"作业之间互斥"由**外部服务器的
|
||||
自由值**承担——作业 A 占 3 个 license,服务器自由值降到 1,调度器下一轮
|
||||
看到的就是 1。调度器自己的账本(`sharedInUse`)对 EXTERNAL 资源**记了但
|
||||
准入时不看**。两个推论:
|
||||
|
||||
- 自由值的推送周期是暴露窗口:同一个调度轮内连发多个申请同一 EXTERNAL
|
||||
资源的作业,可能在自由值还没降下来时都获准入(真实 license 服务器会在
|
||||
checkout 时兜底拒绝,见 §11.2 licjob 的 exit 99)。生产上要么接受这个
|
||||
窗口,要么在提交脚本里隔开(≥ poll_interval)。
|
||||
- §7 的 limit vres 是**非 EXTERNAL** 的 GLOBAL 资源,走完整
|
||||
`inuse + uncomit + wanted` 公式,配额在调度器本地即时扣减——不依赖
|
||||
推送,同一轮内也严格生效。
|
||||
|
||||
### 1.3 失败语义(fail-open 采集 + fail-conservative 调度)
|
||||
|
||||
- **采集侧 fail-open**:脚本一轮失败(超时、无输出、输出不可解析)时,
|
||||
xceesd/elim 保留上一个好值继续报,并打一次 WARN;不主动把池子清零引发
|
||||
误停摆。elim 的特例:**从未成功过**的 elim 源失败时返回 "0"(池子从零
|
||||
开始),**有过旧值**的 elim 源失败时返回 ""(解析为 0,值归零)——详见
|
||||
§6.4。
|
||||
- **stale 升级**:持续失败超过 `stale_limit`(xceesd 默认 150 秒)后,每轮
|
||||
追加 STALE WARN;`xceadmin extres status` 里对应源标记 `"stale": true`。
|
||||
从未有过值的源不判 stale。
|
||||
- **调度侧 fail-conservative**:xceesd 未上线(或还没推过值)时,全局池读
|
||||
0,申请该资源的作业 **PEND**(pending reason `NO_RESOURCE`,detail 带
|
||||
资源名),而不是放行。宁可排队,不超发。
|
||||
- **配置不播种**:`resources.yaml` 里 EXTERNAL 资源**不写 value**——写了也
|
||||
会被忽略(`seed_sharedinst_from_config` 对 EXTERNAL 跳过)。池值只来自
|
||||
daemon,避免配置里的幻影容量掩盖 daemon 掉线。
|
||||
|
||||
### 1.4 与 LSF 的路线差异(背景)
|
||||
|
||||
LSF 的 `bld`(License Scheduler daemon)+ `elim` 是"采集器 → 专门 license
|
||||
分发器 → 分布式记账"路线;XCE 的路线是把 license free 值直接当作一种**全局
|
||||
共享资源值**灌进统一资源模型,复用既有的 resval 推送链、准入判式和 limit
|
||||
策略层。因此 fairshare/reserve 等策略对 license 资源天然生效(它们作用在
|
||||
作业选择层,与资源来源无关);池容量 itself 的分发由 free 值 + EXTERNAL
|
||||
记账规则完成。当前版本暂未做 license 级 fairshare(按项目对池子的历史用量
|
||||
再分配),如需要可配 per-project/per-queue 配额近似实现(§7)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 集群侧资源声明
|
||||
|
||||
### 2.1 resources.yaml
|
||||
|
||||
全局腿资源在 `resources.yaml` 声明,关键三件事:`type: numeric`、
|
||||
`resourcemap` 指到 `external`、**不写 value**:
|
||||
|
||||
```yaml
|
||||
resources:
|
||||
- name: extlic
|
||||
description: externally reported license pool
|
||||
type: numeric
|
||||
interval: 0
|
||||
consumable: true
|
||||
order: decrease
|
||||
resourcemap:
|
||||
- location: [external] # → SHARED|GLOBAL|EXTERNAL (0x1C)
|
||||
```
|
||||
|
||||
各字段含义:
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
|------|------|------|
|
||||
| `name` | ✅ | 资源名,调度/提交时引用 |
|
||||
| `type` | ✅ | numeric(外部资源均为数值型) |
|
||||
| `consumable` | ❌ | true = 计量消耗型(license 用 true) |
|
||||
| `resourcemap[].location` | ✅ | `[external]` = 全局腿;`[all]` = SHARED\|GLOBAL 非 EXTERNAL;`[default]` = 普通动态资源 |
|
||||
| `interval` | ❌ | 解析但当前无消费方(见 §12) |
|
||||
| `release` | ❌ | 动态资源回收到 worker 池的标记(普通动态资源用) |
|
||||
|
||||
JSON schema(`src/configs/schema/resources.schema.json`)强制 `name`/`type`
|
||||
必填,resourcemap 项允许 `value`/`location` 数组。
|
||||
|
||||
**常见错误**:
|
||||
|
||||
- 在 EXTERNAL 资源的 resourcemap 里写 `value:` —— 没有意义,seed 阶段会跳
|
||||
过(§1.3),且容易误以为配置兜了底。
|
||||
- `location` 写 `[default]` 却想让 xceesd 推值 —— 推送会被 opupd 的
|
||||
"SHARED 即收"守卫拒绝(extres 角色推的值只收 SHARED 资源),见 §10.4。
|
||||
|
||||
### 2.2 Flag 语义速查
|
||||
|
||||
flags 在 `src/xceadmin/src/xcecommon/mapping.py` 生成,bit 含义:
|
||||
|
||||
| Flag | Bit | 含义 | 何时打上 |
|
||||
|------|-----|------|----------|
|
||||
| BUILTIN | 0x01 | 内置资源 | resources.yaml 里 `builtin: true` |
|
||||
| DYNAMIC | 0x02 | 动态(有 resourcemap/location) | 声明了 resourcemap |
|
||||
| GLOBAL | 0x04 | 全局共享池 | location 含 all/external |
|
||||
| SHARED | 0x08 | 值来自共享实例(sharedInst) | location 含 all/external |
|
||||
| EXTERNAL | 0x10 | 外部 daemon 推 free 值 | location 含 external |
|
||||
| RELEASE | 0x20 | 作业结束值回收到来源 | `release: true` |
|
||||
| CONSUMABLE | 0x80 | 计量消耗型 | `consumable: true` |
|
||||
| LIMIT | 0x100 | 限额派生的虚拟资源 | limits 实例化自动打 |
|
||||
|
||||
`location: [all]` 与 `location: [external]` 的区别就是有没有 EXTERNAL 位,
|
||||
决定准入公式走哪条分支(§1.2)。
|
||||
|
||||
### 2.3 主机腿资源声明
|
||||
|
||||
elim 落地的资源用普通动态资源声明(location 用 `[all]` 或 `[default]`),
|
||||
**值来自每台主机的 elim 脚本**:
|
||||
|
||||
```yaml
|
||||
resources:
|
||||
- name: dynres1
|
||||
description: per-host dynamic resource from elim
|
||||
type: numeric
|
||||
interval: 0
|
||||
resourcemap:
|
||||
- location: [all] # 每主机都有各自的值
|
||||
```
|
||||
|
||||
> ⚠️ 主机腿资源**不要**加 `consumable: true` + 依赖调度器算 inuse——elim 推
|
||||
> 的同样是"free 值"(脚本返回的数直接就是该主机的可用量),调度器把它当作
|
||||
> 该主机的资源值参与 `sched_check_host_satisfy_` 的 host 腿判定。申请值的
|
||||
> 扣减由调度器 uncomit 跟踪(同普通 host 资源)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 配置构建与下发
|
||||
|
||||
用 `xceadmin` 把 YAML 构建成 cluster.bin 并推给 controller:
|
||||
|
||||
```bash
|
||||
# 1. 构建(CONFIGS_DIR 下可放 7 类 YAML:xce/resources/queues/users/
|
||||
# hosts/scaler/limits——hosts.yaml 承载 hosts+hostgroups 两个键;
|
||||
# 缺哪个文件该节为空不算错,但 push 会把对应配置清掉,实践上给全套)
|
||||
xceadmin config build /path/to/configs -o cluster.bin
|
||||
|
||||
# 2. 预览(探针,不落账)
|
||||
xceadmin config push cluster.bin --dry-run
|
||||
|
||||
# 3. 推送(注意:push/dump 的参数是 build 产物 cluster.bin,不是 YAML 目录)
|
||||
xceadmin config push cluster.bin
|
||||
```
|
||||
|
||||
- controller 地址:`--controller host:port` 显式指定,或环境变量
|
||||
`XCE_CONTROLLER_PEERS` > `XCEADMIN_CONTROLLER` > 默认 `localhost:9991`。
|
||||
- 推送后**必须重启 apiserver** 才能读到新定义(apiserver 的定义 store 只在
|
||||
join 时的 config push 里建立;这是已知运维约束)。
|
||||
- 单节点集群 `push` 可能报 `ackedCount == 0` 误报(push 实际成功,以
|
||||
controller 日志 gen/tag 为准)——不要因此反复重推。
|
||||
- 验证:
|
||||
|
||||
```bash
|
||||
xceadmin config dump cluster.bin # 看 build 产物
|
||||
# resources 段的 extlic 行应长这样(真实输出):
|
||||
# name=extlic type=numeric order=decrease desc='...' consumable=True
|
||||
# release=False external=True shared=true distributions=[external]=(reported)
|
||||
# external=True 只在 EXTERNAL 资源上出现;absent 即普通资源
|
||||
# limits 段能看到 resname=extlic value=3.0 per_project=True 之类
|
||||
```
|
||||
|
||||
- 调度器对资源定义的感知:config push 激活后调度器会被 re-push,但**老版本
|
||||
调度器需重启才拾取资源新定义**;生产升级路径保持"push 后重启 scheduler
|
||||
+ apiserver"最稳。
|
||||
|
||||
---
|
||||
|
||||
## 4. 全局腿:xceesd 部署
|
||||
|
||||
### 4.1 esd.yaml
|
||||
|
||||
xceesd 的配置文件(默认 `/etc/xce/esd.yaml`):
|
||||
|
||||
```yaml
|
||||
# 必填二选一:单 controller 或 peers 列表
|
||||
controller: "172.31.1.30:9990"
|
||||
# peers: "172.31.1.30:9990,172.31.1.31:9990"
|
||||
|
||||
# 可选
|
||||
poll_interval: 10 # 采集+推送轮询间隔(秒),≤0 视为 30
|
||||
stale_limit: 60 # 超过此秒数未成功升级为 STALE(秒)
|
||||
status_file: /tmp/e2e/esd-status.json # 状态 JSON 落点
|
||||
|
||||
resources:
|
||||
- name: extlic # 必填,须与 resources.yaml 声明一致
|
||||
collector: script # 必填,当前唯一类型
|
||||
command: /tmp/e2e/fake_lic.sh extlic # 必填,采集命令
|
||||
interval: 10 # 可选:解析但当前 poll 循环未消费(见 §12)
|
||||
stale_limit: 60 # 可选:源级覆盖 daemon 级
|
||||
```
|
||||
|
||||
字段约束(`src/esd/src/esd_config.c`):
|
||||
|
||||
| 字段 | 必填 | 约束 |
|
||||
|------|------|------|
|
||||
| `controller` | 与 peers 二选一 | `host:port`,port 1-65535 |
|
||||
| `peers` | 与 controller 二选一 | 逗号分隔 `host:port` |
|
||||
| `poll_interval` | ❌ | ≤0 → 30(在 main.c 兜底) |
|
||||
| `stale_limit` | ❌ | 默认 150 |
|
||||
| `status_file` | ❌ | 默认 `/var/run/xce/esd-status.json` |
|
||||
| `resources[].name` | ✅ | |
|
||||
| `resources[].collector` | ✅ | 当前只有 `script` |
|
||||
| `resources[].command` | ✅ | |
|
||||
| `resources[].interval` | ❌ | **解析但未消费**(§12) |
|
||||
| `resources[].stale_limit` | ❌ | 覆盖 daemon 默认 |
|
||||
|
||||
未知键忽略;文件不存在 → `-ENOENT`;结构非法 → `-EINVAL`;均 exit 1。
|
||||
|
||||
### 4.2 启动与 CLI
|
||||
|
||||
```bash
|
||||
xceesd -c /etc/xce/esd.yaml -l /tmp/xceesd.log -v
|
||||
```
|
||||
|
||||
| 选项 | 默认 | 说明 |
|
||||
|------|------|------|
|
||||
| `-c` / `--config` | `/etc/xce/esd.yaml` | 配置文件 |
|
||||
| `-l` / `--logfile` | `/tmp/xceesd.log` | 日志(16MB × 4 轮转) |
|
||||
| `-v` / `--verbose` | off | debug 日志 |
|
||||
| `--script-timeout` | 10000 (ms) | 单次脚本采集的看门狗上限 |
|
||||
|
||||
SIGINT/SIGTERM 优雅退出。
|
||||
|
||||
### 4.3 运行时行为
|
||||
|
||||
1. **join**:以 `extres` 角色 join controller(默认第一次连上的端点)。
|
||||
2. **每轮 poll**:对每个 source 执行脚本 → 解析 → 与上次值比较
|
||||
(**debounce**:值没变就不推,controller 侧 LAST_UPDATED 也不刷新——这
|
||||
是特性不是 bug,`extres status` 的 age 才是新鲜度真值)。
|
||||
3. **stale 判定**:`now - last_ok_time > stale_limit` → STALE WARN +
|
||||
status JSON 置 `stale: true`。
|
||||
4. **连接断开**:断开标志置位后每轮强制推一次(debounce 旁路),唤醒重连。
|
||||
5. **重连/rejoin**(bug-1978 修复后语义):重连成功先**重新 join**(新端点
|
||||
的新连接不 join 直接推会被拒 `-EPERM`),然后**全量重推**所有源(不管
|
||||
值有没有变)——controller 重启或网络抖动后池子自动恢复,无需人工干预。
|
||||
6. **status JSON**:每轮原子写(tmp + rename),字段见 §9.1。
|
||||
|
||||
### 4.4 部署约束
|
||||
|
||||
- **xceesd 必须与它的采集脚本同主机**(脚本路径按本机解析;license 场景
|
||||
通常意味着 xceesd 部署在能访问 license 服务器的主机上)。
|
||||
- **当前支持单 xceesd 实例**(无 HA/多实例去重),见 §12。
|
||||
- 当前版本全局腿**只支持"一个资源名 = 一个全局池"**。若需要"部分主机共享
|
||||
一个池"(host 子集池),见 §12。
|
||||
|
||||
---
|
||||
|
||||
## 5. 采集脚本契约
|
||||
|
||||
xceesd 和 elim 共用同一套脚本解析逻辑(`src/esd/src/esd_script.c` 与
|
||||
`src/worker/src/elim.c`),契约如下:
|
||||
|
||||
### 5.1 输出格式
|
||||
|
||||
stdout 打印**一行**,两种形式都接受:
|
||||
|
||||
```
|
||||
extlic 3 # "<name> <value>"
|
||||
3 # 裸值
|
||||
```
|
||||
|
||||
解析器是 token 跳跃式:把 stdout 按 token 拆,跳过非数字 token 找到第一个
|
||||
`strtod` 可解析的段作为值——所以 `value is 3` 也行,`extlic 3` 和
|
||||
`3 extlic` 都能解析。stderr 丢弃(xceesd)或 /dev/null(elim),不影响
|
||||
结果。无输出 / 输出无数字 → 采集失败(isnan),走 fail-open 路径。
|
||||
|
||||
### 5.2 运行环境
|
||||
|
||||
- 由 daemon 用 `posix_spawn("/bin/sh -c <command>")` 执行(**禁 fork**,
|
||||
daemon 多线程环境);脚本继承 daemon 的环境变量。
|
||||
- **看门狗**:脚本超过 `--script-timeout`(默认 10 秒)被 SIGKILL,按失败
|
||||
处理。轮询切片 100ms(poll(2)),daemon 主循环不阻塞。
|
||||
- **脚本返回的是 free 值**(还剩多少可用),不是 total、不是 inuse——见
|
||||
§1.2。
|
||||
|
||||
### 5.3 脚本编写要点
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
# 例:从 license 服务器拿剩余 license 数。
|
||||
# 失败路径务必输出一个保守值(如 0)或什么都不输出——
|
||||
# 输出垃圾数字会污染池子。
|
||||
free=$(query_license_server extlic 2>/dev/null) || exit 1
|
||||
echo "extlic $free"
|
||||
```
|
||||
|
||||
- 脚本自身要快(看门狗 10s);license 服务器查询建议加超时。
|
||||
- 失败时 `exit 1` 且**不输出数字**,比输出错误猜测值安全(fail-open 会保
|
||||
旧值,不会拿错误值覆盖)。
|
||||
- 别往 stdout 打任何诊断信息(日志去 stderr)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 主机腿:elim 采集器
|
||||
|
||||
### 6.1 配置
|
||||
|
||||
worker 节点上的 `/etc/xce/xcecd.yaml`(或 `-c` 指定的文件):
|
||||
|
||||
```yaml
|
||||
external_resources:
|
||||
- name: dynres1
|
||||
command: /opt/xce-denix/bin/elim-dynres1.sh
|
||||
interval: 30 # 秒;0(或省略)= 每个 send tick 都重跑脚本
|
||||
```
|
||||
|
||||
- `name`/`command` 必填;`interval` 可选,默认 0。
|
||||
- 文件不存在或缺必填字段:xcecd **启动即退出**(fail-loud-at-load,
|
||||
stderr 报 `-ENOENT`/`-EINVAL`)——坏配置不会静默空跑。
|
||||
- 上限 `ELIM_MAX_SOURCES = 16` 个源/主机。
|
||||
|
||||
### 6.2 与内置 load index 的关系
|
||||
|
||||
elim 源注册进 worker `resource_sync` 的 load-index 注册表(与 11 个内置
|
||||
指标 r15s/r1m/r15m/ut/pg/ls/it/swap/mem/tmp/io 同一张表),随既有的
|
||||
15-tick(15 秒)上报链推给 controller。注册顺序上先保证注册表容量就绪
|
||||
(`resource_sync_ensure_builtin_load_indices`),避免 capacity-0 拒绝。
|
||||
|
||||
**名字冲突保护**:
|
||||
|
||||
- 撞内置名(`mem`/`r15s`/`tmp`/…)→ `-EEXIST`,xcecd 启动报错退出。
|
||||
- 撞已注册的 elim 名 → 同样 `-EEXIST`。
|
||||
|
||||
### 6.3 interval 缓存语义
|
||||
|
||||
elim 的 `interval` 与 xceesd 的**不同**:它是**脚本重跑的门控**,不是推送
|
||||
节奏:
|
||||
|
||||
- `interval: 0`:每次收集(每 15s tick)都重跑脚本。
|
||||
- `interval: N`(>0):距上次成功执行不足 N 秒时,直接复用缓存的脚本
|
||||
返回值,跳过执行;推送节奏仍固定 15s tick。
|
||||
|
||||
即 elim 源的**上报节奏恒为 15s**,`interval` 只控制脚本执行频率(省脚本
|
||||
开销)。
|
||||
|
||||
### 6.4 失败语义(与 xceesd 的差异)
|
||||
|
||||
elim 的 fail-open 路径有两档(`elim_getter_run`):
|
||||
|
||||
| 场景 | getter 返回 | 生效值 |
|
||||
|------|-------------|--------|
|
||||
| 从未成功过 + 本轮失败 | `"0"` | 0(池子从零开始) |
|
||||
| 有过旧值 + 本轮失败 | `""` | 0(**值归零**,非保旧值) |
|
||||
| 从未成功过 + 从未失败 | 无值(不注册前不收集) | — |
|
||||
|
||||
> ⚠️ 注意:elim 失败时**值归零**而非保旧值——这与 xceesd 的"保旧值 +
|
||||
> STALE"不同。主机腿的语义是"这台主机的量现在拿不到,就当没有"。调度侧
|
||||
> 效果是申请该主机资源的作业 PEND(fail-conservative),不会超发。
|
||||
> interval>0 的源在缓存窗口内的"失败"其实不会发生(根本没跑脚本);一旦
|
||||
> 窗口过后重跑失败,缓存值即被置零。
|
||||
|
||||
---
|
||||
|
||||
## 7. 策略层:limits 配额
|
||||
|
||||
外部资源可以进 limits.yaml 做按项目/队列的配额(E2 Phase 3):
|
||||
|
||||
```yaml
|
||||
limits:
|
||||
- name: extlic_share
|
||||
projects:
|
||||
members: [projA, projB]
|
||||
resname: extlic
|
||||
value: 3.0 # projA+projB 合计最多 3 个
|
||||
per_project: true # → 每项目各 3 个
|
||||
|
||||
- name: extlic_qdist
|
||||
queues:
|
||||
members: [normal, night]
|
||||
resname: extlic
|
||||
value: 4.0
|
||||
per_queue: true # → 每队列各 4 个
|
||||
```
|
||||
|
||||
机制:limit 实例化为一个**虚拟资源**(vres),名字格式
|
||||
`limit=<name>[/u=<user>][/q=<queue>][/p=<project>]`(只有对应 per_* 打开的
|
||||
段会出现),flags = `LIMIT|CONSUMABLE|RELEASE|SHARED|GLOBAL`。作业提交时
|
||||
按其 project/queue 挂上对应 vres 的 rusage 需求,调度时同样走 GLOBAL 池
|
||||
准入判定。
|
||||
|
||||
- 超限时 PEND,pending reason:
|
||||
- 全局 limit 超限 → `LIMIT_GLOBAL`(值 4)
|
||||
- 底层资源不足 → `NO_RESOURCE`(值 2)
|
||||
- 项目不在任何 limit 的 `projects.members` 里 → **不受该 limit 约束**,只
|
||||
受底层池容量约束(某项目免疫配额是特性)。
|
||||
- `limits.yaml` 的 `projects.members` 不做 catalog 校验(无 projects.yaml
|
||||
强校验),写错项目名不会在 build 时报错——测试时注意。
|
||||
|
||||
schema(`src/configs/schema/limits.schema.json`):`name`/`resname`/`value`
|
||||
必填;`percent` 0-1;`per_project`/`per_queue` 等布尔。
|
||||
|
||||
---
|
||||
|
||||
## 8. 作业提交
|
||||
|
||||
### 8.1 基本语法
|
||||
|
||||
```bash
|
||||
# 全局 license 池
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=1]" -- sleep 3600
|
||||
|
||||
# 主机 elim 资源
|
||||
xce jobs submit -R "rusage[dynres1=15]" -- sleep 3600
|
||||
|
||||
# 多资源、per 类型
|
||||
xce jobs submit -R "rusage[extlic=1, mem=1024:per_host]" -- sleep 3600
|
||||
```
|
||||
|
||||
### 8.2 ⚠️ 必须用方括号
|
||||
|
||||
`rusage[...]` 的方括号是强制的。圆括号 `rusage(extlic=1)` 会走 select 语法的
|
||||
回退解析路径被吞掉,导致整个提交请求硬失败(bug-1887 家族)。手册级规则:
|
||||
**永远 `rusage[...]`**。
|
||||
|
||||
### 8.3 per 类型语义
|
||||
|
||||
`rusage[res=N:per_TYPE]` 的 TYPE:
|
||||
|
||||
| per 类型 | 语义 | 值计算 |
|
||||
|----------|------|--------|
|
||||
| `per_task`(默认) | 每任务槽 | N × nslots |
|
||||
| `per_job` | 每作业一份 | N |
|
||||
| `per_host` | 每主机一份 | N × nhosts |
|
||||
|
||||
省略 per 类型时继承 caller 默认(`PER_DEFAULT` = per_task)——即
|
||||
`-R "rusage[extlic=1]"` 单槽作业申请 1,4 槽作业申请 4。
|
||||
|
||||
`duration=N[s|m|h]` 和 `decay=0|1` 目前**可解析但只进指纹/展示,不参与
|
||||
准入算术**(§12)。
|
||||
|
||||
### 8.4 pending reason 解读
|
||||
|
||||
- `NO_RESOURCE` (2):底层池不够(xceesd 没推值/池被占满),detail 会带资源名。
|
||||
- `LIMIT_GLOBAL` (4):limit vres 配额超限。
|
||||
- CLI 当前 pending_reason 列可能显示 `-`(展示链缺口,§12);pending
|
||||
reason 的完整内容(reason 值 + detail 资源名)在 apiserver JSON
|
||||
(`GET /xce/v1/jobs` 的 pending_reason 字段)与调度器日志里可见。
|
||||
|
||||
---
|
||||
|
||||
## 9. 运维观测
|
||||
|
||||
### 9.1 xceadmin extres status
|
||||
|
||||
```bash
|
||||
xceadmin extres status
|
||||
```
|
||||
|
||||
读本机 status JSON(默认 `/var/run/xce/esd-status.json`,或 esd.yaml 的
|
||||
`status_file`)。**该命令只读本机文件**——多节点部署时要 ssh 到 xceesd
|
||||
所在节点执行(§12)。
|
||||
|
||||
输出解读(真实渲染格式,`_format_extres_status`):
|
||||
|
||||
```
|
||||
daemon: xceesd (pid 12345)
|
||||
started at: 2026-10-28T10:00:00 (up 3600s)
|
||||
pushes: 350 ok, 2 failed
|
||||
sources:
|
||||
extlic: value=3 age=12s
|
||||
```
|
||||
|
||||
- `value=V age=Ns`:V = 最后成功采集的值;age = 距该值的秒数。
|
||||
- `-- STALE` 后缀:超过 stale_limit,源值得怀疑(xceesd 还在推旧值,调度
|
||||
侧继续放行——这时要人工介入看脚本/license 服务器)。
|
||||
- `extlic: no value yet`:daemon 起来后从未成功采到值(池子视为 0,作业
|
||||
PEND)。
|
||||
- `sources: (none configured)`:esd.yaml 没配 resources。
|
||||
- `pushes: N failed` 持续增长:controller 连接问题(对照 §10.2/§10.3)。
|
||||
- 另有 `--status-file PATH` 选项覆盖默认路径。
|
||||
|
||||
status JSON 完整字段:`daemon`/`pid`/`started_at`/`generated_at`/
|
||||
`pushes_ok`/`pushes_fail`/`sources[{name, last_value, last_ok_time, stale}]`。
|
||||
|
||||
### 9.2 资源定义与值观测
|
||||
|
||||
```bash
|
||||
# 定义(-l/--verbose 显示 detail 列)
|
||||
xce resources definition list -l
|
||||
# RESOURCE: extlic
|
||||
# TYPE ORDER INTERVAL LAST_UPDATED BUILTIN DYNAMIC RELEASE CONSUMABLE
|
||||
# Numeric Decr 0 Oct 28 14:04 false false false true
|
||||
# LAST_UPDATED:"-" = 从未推过;EXTERNAL 资源随推送刷新(debounce:值没变
|
||||
# 不推,稳定值下 LAST_UPDATED 也长期不动——新鲜度以 extres status 的
|
||||
# age 为准);elim 资源定义 LAST_UPDATED 一般也是 "-"(值走 distribution)
|
||||
|
||||
# 分布(-t static=配置声明的静态值,-t dynamic=live 推送值;全局资源的
|
||||
# LOCATION 列显示 "-",主机资源显示主机名)
|
||||
xce resources distribution list -t dynamic
|
||||
# dynres1 22 t2
|
||||
# extlic 4 -
|
||||
|
||||
# 主机视角(每个主机一节的 CURRENT LOAD 表只渲染 12 个内置列
|
||||
# r15s..slots——elim 自定义指标**不**出现在这个表里;主机腿的值
|
||||
# 用上面的 distribution list -t dynamic 看主机名落点)
|
||||
xce hosts list -a
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 故障处理
|
||||
|
||||
### 10.1 xceesd 掉线(进程挂/主机挂)
|
||||
|
||||
**现象**:作业 PEND,pending reason `NO_RESOURCE`(detail 带资源名);
|
||||
`extres status` 读不到(文件陈旧)或 pushes 不再增长。
|
||||
|
||||
**语义**:xceesd 掉线后没有新值进来,但**旧值仍在**(controller 的
|
||||
sharedInst 不会因 daemon 掉线自动清零)。调度器会继续按旧值放行作业——
|
||||
这是有意的 fail-open:license 服务器真实状态未知时,按最后已知值走。
|
||||
风险窗口靠观测面发现:`extres status` 的 age 持续增长、超过 stale_limit
|
||||
后 STALE 标记出现(status 文件本身随最后一轮 poll 冻结,不会再更新)。
|
||||
|
||||
**处理**:
|
||||
|
||||
```bash
|
||||
# 1. 到 xceesd 主机看进程/日志
|
||||
ps aux | grep [x]ceesd
|
||||
tail -50 /tmp/xceesd.log
|
||||
|
||||
# 2. 重启(会自动 rejoin + 全量重推,池子自动恢复)
|
||||
xceesd -c /etc/xce/esd.yaml -l /tmp/xceesd.log &
|
||||
```
|
||||
|
||||
### 10.2 controller 重启
|
||||
|
||||
xceesd 检测到连接断开会自动 re-join + 全量重推(bug-1978 修复的语义),
|
||||
**无需重启 xceesd**。确认方式:`extres status` 的 pushes ok 继续增长。
|
||||
|
||||
**但调度器要重启**:调度器 rejoin 对 sharedInst 的重建有已知问题
|
||||
(stale join 卡死),controller 重启后按标准流程**调度器随 controller 一并
|
||||
重启**(既有运维约束,不特属于本特性)。
|
||||
|
||||
### 10.3 config push 之后
|
||||
|
||||
1. **重启 apiserver**(定义 store 只吃 join 时 config push)。
|
||||
2. 调度器激活 re-push 会刷新 live 定义,但稳妥起见**重启 scheduler**。
|
||||
3. xceesd **无需**重启(它推值走的是 live 通道,与定义 store 无关);
|
||||
若新资源是第一次出现,xceesd 下一次推送即落账。
|
||||
|
||||
### 10.4 推送被拒(opupd -EPERM)
|
||||
|
||||
`/var/log` 下 controller 日志出现 extres 值被拒:通常是 esd.yaml 里的
|
||||
`name` 与 resources.yaml 声明的 location 不匹配——extres 角色推的值只收
|
||||
**SHARED** 资源("SHARED 即收"守卫)。检查:resources.yaml 是否
|
||||
`location: [external]` 或 `[all]`,config push + apiserver/scheduler 重启
|
||||
是否做完。
|
||||
|
||||
### 10.5 采集脚本挂死
|
||||
|
||||
看门狗 10 秒 SIGKILL,按失败处理,走 fail-open(保旧值 + WARN)。若脚本
|
||||
持续挂死,stale_limit 后升级 STALE。排查:脚本是否在等 license 服务器
|
||||
响应无超时——**给脚本内部的网络调用加超时**,别依赖看门狗兜底。
|
||||
|
||||
---
|
||||
|
||||
## 11. 测试指南(E2E 配方)
|
||||
|
||||
以下配方在 t1/t2/t3 测试集群实测通过(2026-10-27/28)。用假脚本即可做全
|
||||
链路验证,不依赖真实 license 服务器。
|
||||
|
||||
### 11.1 准备
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/e2e
|
||||
```
|
||||
|
||||
**假 license 脚本** `/tmp/e2e/fake_lic.sh`——用"活 pid marker 文件池"模拟
|
||||
license 占用:`held.<pid>` marker 的进程活着 = 一份 license 被持有;进程
|
||||
死了(TERM/KILL/exit 任何方式)`/proc/<pid>` 消失,下次读取自动回收,
|
||||
计数永不漂移。TOTAL=4:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Fake license collector. Pool = marker files held.<pid>; a license is held
|
||||
# iff its pid is alive. Death (TERM/KILL/exit) releases automatically, so the
|
||||
# count can never drift. Stale markers self-clean on every read.
|
||||
DIR=/tmp/e2e/licpool
|
||||
TOTAL=4
|
||||
mkdir -p "$DIR"
|
||||
free=$TOTAL
|
||||
for f in "$DIR"/held.*; do
|
||||
[ -e "$f" ] || continue
|
||||
pid=${f##*.}
|
||||
if [ -d "/proc/$pid" ]; then
|
||||
free=$((free-1)) # alive (works cross-user; kill -0 confuses EPERM with ESRCH)
|
||||
else
|
||||
rm -f "$f" # gone -> clean up marker
|
||||
fi
|
||||
done
|
||||
echo "extlic $free"
|
||||
```
|
||||
|
||||
**占坑 wrapper** `/tmp/e2e/licjob.sh`——作业本体包一层:占一份 license
|
||||
(lock 目录互斥 + `/proc` 活性清扫),占不到 exit 99,占到了就执行真正的
|
||||
作业命令。作业进程死亡 = marker 自动失效,**无需 trap 清理**:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Fake license checkout: hold 1 license for the duration of "$@".
|
||||
# The license IS a pid-keyed marker file; holding ends when this process dies
|
||||
# (any way, incl. SIGKILL). No trap needed — accounting is liveness-based.
|
||||
DIR=/tmp/e2e/licpool
|
||||
TOTAL=4
|
||||
mkdir -p "$DIR"
|
||||
while ! mkdir "$DIR.lock" 2>/dev/null; do sleep 0.2; done
|
||||
for f in "$DIR"/held.*; do
|
||||
[ -e "$f" ] || continue
|
||||
pid=${f##*.}
|
||||
[ -d "/proc/$pid" ] || rm -f "$f" # /proc dir gone = truly dead (works cross-user;
|
||||
done # kill -0 cannot distinguish EPERM from ESRCH)
|
||||
count=$(ls "$DIR"/held.* 2>/dev/null | wc -l)
|
||||
if [ "$count" -ge "$TOTAL" ]; then
|
||||
rmdir "$DIR.lock"
|
||||
echo "licjob: no license available (free=0)" >&2
|
||||
exit 99
|
||||
fi
|
||||
if ! echo $$ > "$DIR/held.$$" 2>/dev/null; then
|
||||
rmdir "$DIR.lock"
|
||||
echo "licjob: cannot write marker in $DIR (perm?)" >&2
|
||||
exit 99
|
||||
fi
|
||||
rmdir "$DIR.lock"
|
||||
echo "licjob: checked out 1 license (free now $((TOTAL - count - 1)))"
|
||||
"$@"
|
||||
exit $?
|
||||
```
|
||||
|
||||
用法是**包住作业命令**:`-- /tmp/e2e/licjob.sh sleep 3600`(licjob 占 1 份
|
||||
license,然后跑 `sleep 3600`;licjob 进程活着多久,license 持有多久)。
|
||||
|
||||
> ⚠️ 两个实测过的坑:
|
||||
> 1. 活性检查用 `/proc/<pid>` 目录存在性而非 `kill -0`——后者在跨用户
|
||||
> (worker 以别的 uid 跑作业)时把 EPERM 当活着,死 marker 永不回收。
|
||||
> 2. 不要用 SIGSTOP 冻结作业进程来"保持占用"——冻结进程的 marker 照样被
|
||||
> 认活,但 kill 回收语义就测不到了;回收测试直接 kill。另外 SIGSTOP
|
||||
> 冻结 status JSON 文件本身会让 `extres status` 读到假 false。
|
||||
|
||||
**esd.yaml 测试样例** `/tmp/e2e/esd.yaml`:
|
||||
|
||||
```yaml
|
||||
controller: "172.31.1.30:9990"
|
||||
poll_interval: 10
|
||||
stale_limit: 60
|
||||
status_file: /tmp/e2e/esd-status.json
|
||||
resources:
|
||||
- name: extlic
|
||||
collector: script
|
||||
command: /tmp/e2e/fake_lic.sh extlic
|
||||
```
|
||||
|
||||
### 11.2 场景 1:全局 license 池 E2E
|
||||
|
||||
前置:resources.yaml 声明 `extlic`(§2.1),config push + 重启 apiserver/
|
||||
scheduler,xceesd 跑在 t2(脚本同主机)。
|
||||
|
||||
**记账模型先读一遍**(配方为什么这样设计):调度器侧的账与 fake 池的账是
|
||||
两本——
|
||||
|
||||
- 调度器侧:EXTERNAL 只看推送来的 total ≥ uncomit + wanted。`uncomit` 是
|
||||
每次分配尝试的暂存簿(作业派发即清),RUN 作业的占用**不**进调度器准入
|
||||
——靠自由值下降体现(§1.2 跨作业记账分工)。
|
||||
- fake 池侧:licjob 进程活着 → 1 个 marker → free 降 1。**每个 licjob
|
||||
进程占 1 份,不管 rusage 申请多少**。
|
||||
|
||||
所以用 rusage[extlic=3] 的作业时:调度器第一轮 total=4 ≥ 3 放行,之后
|
||||
推送值降到 3(1 个 marker),后续作业按 3 算。想要"精确对账"的场景用
|
||||
rusage[extlic=1] 的作业最干净(调度器扣 1、marker 扣 1,两本账一致)。
|
||||
|
||||
```bash
|
||||
# 1. 池子在线
|
||||
ssh t2 'xceadmin extres status'
|
||||
# 期望:value=4 (TOTAL),age 正常,无 STALE
|
||||
|
||||
# 2. 大块申请 + 超额(两本账的暴露窗口演示)
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=3]" -- /tmp/e2e/licjob.sh sleep 3600
|
||||
# 期望:RUN(第一轮 total=4 ≥ 0+3)
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=2]" -- /tmp/e2e/licjob.sh sleep 3600
|
||||
# 紧跟着提交(自由值还没降):total=4 ≥ 0+2 → RUN 也可能拿到;
|
||||
# 但 fake 池只剩 4-1-1=2,licjob 拿不到 marker 会 exit 99 → 作业 EXIT。
|
||||
# 这正是真实 license 服务器 checkout 失败的等价物。
|
||||
# 隔一个 poll_interval 再提交,则看到 total=3(marker 已入账),
|
||||
# 3 ≥ 0+2 → RUN(还能容纳);free 再降到 2。
|
||||
|
||||
# 3. 占满 → PEND(最干净的对账场景:4 个 rusage[extlic=1])
|
||||
for i in 1 2 3 4; do
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=1]" -- /tmp/e2e/licjob.sh sleep 600
|
||||
sleep 12 # ≥ poll_interval,让每次占用都先落到推送值里
|
||||
done
|
||||
# 期望:4 个 RUN,free 一路 3→2→1→0
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=1]" -- /tmp/e2e/licjob.sh sleep 600
|
||||
# 期望:PEND,reason NO_RESOURCE,detail 带 extlic
|
||||
|
||||
# 4. 回填(再准入)
|
||||
# kill 一个 RUN 作业 → marker 回收 → free=1 → 第 5 个作业 RUN
|
||||
|
||||
# 5. 恒超额
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=5]" -- /tmp/e2e/licjob.sh sleep 60
|
||||
# 期望:永远 PEND(TOTAL=4 < 5)
|
||||
```
|
||||
|
||||
### 11.3 场景 2:elim 主机腿 E2E
|
||||
|
||||
前置:`/opt/xce-denix/bin/elim-dynres1.sh`(按主机名给值:t1=11/t2=22/
|
||||
t3=33),xcecd.yaml 配 `external_resources`,三节点都重启 xcecd。
|
||||
|
||||
```bash
|
||||
# 1. 落值
|
||||
xce hosts list -a # t2 的 dynres1 列应显示 22
|
||||
|
||||
# 2. 定向申请
|
||||
xce jobs submit -R "rusage[dynres1=15]" -- sleep 300
|
||||
# 期望:RUN 且落 t2(t1=11/t3=33 不够 15)
|
||||
|
||||
# 3. 超额 PEND + kill 回填 RUN(同场景 1 步骤 3-4)
|
||||
```
|
||||
|
||||
### 11.4 场景 3:per-project 配额 E2E
|
||||
|
||||
前置:limits.yaml 配 `extlic_share`(projA/projB,per_project,value 3),
|
||||
config push + 重启 apiserver/scheduler。注意 limit vres 是**非 EXTERNAL**
|
||||
的 GLOBAL 资源,配额在调度器本地即时扣减,无需等推送——同一轮内连发也
|
||||
严格生效(§1.2)。底层池 TOTAL=4 够用(每个 licjob 占 1 marker,3 个
|
||||
RUN 作业占 3 < 4,不会被池子先卡住)。
|
||||
|
||||
```bash
|
||||
# projA 连发 4 个单 license 作业
|
||||
for i in 1 2 3 4; do
|
||||
xce jobs submit -q normal -P projA -R "rusage[extlic=1]" -- /tmp/e2e/licjob.sh sleep 600
|
||||
done
|
||||
# 期望:前 3 个 RUN,第 4 个 PEND(LIMIT_GLOBAL,detail 带
|
||||
# vres 名 limit=extlic_share/p=projA)
|
||||
|
||||
# kill 一个 → 第 4 个 RUN(配额再准入)
|
||||
|
||||
# projB 免疫性
|
||||
xce jobs submit -q normal -P projB -R "rusage[extlic=1]" -- /tmp/e2e/licjob.sh sleep 600
|
||||
# 期望:RUN(projB 有自己的 3 个配额,与 projA 用量无关)
|
||||
```
|
||||
|
||||
### 11.5 回归清单
|
||||
|
||||
提交相关改动前跑:
|
||||
|
||||
```bash
|
||||
# C 侧单元/白盒(meson test 名:"esd core test" / "worker elim test" /
|
||||
# "worker resource_sync test";调度器 suite 在 src/scheduler)
|
||||
ninja -C build.dbg
|
||||
meson test -C build.dbg 'esd core test' 'worker elim test' 'worker resource_sync test'
|
||||
|
||||
# Go 侧
|
||||
cd src/frontend && make test # 含 config dump external 渲染等
|
||||
```
|
||||
|
||||
相关测试文件:`src/esd/testsuite/test_esd_core.c`(配置/解析/stale/重连
|
||||
flag/status 写)、`src/worker/testsuite/test_elim.c`(配置/解析/注册表/
|
||||
看门狗/interval 缓存)、调度器侧 EXTERNAL 判式与 limit vres 白盒测试。
|
||||
|
||||
---
|
||||
|
||||
## 12. 已知限制
|
||||
|
||||
| # | 限制 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | 单 xceesd 实例 | 无 HA、无多实例去重;xceesd 挂了池子停在旧值(fail-open),观测靠 STALE |
|
||||
| 2 | 无手动覆盖入口 | 没有改池值的 REST/CLI(调试时只能改脚本输出) |
|
||||
| 3 | host 子集池不支持 | 全局池是全集群一份;"t1/t2 共享 5 个 license、t3 另有 2 个"需拆成两个资源名 |
|
||||
| 4 | esd per-source `interval` 未消费 | esd_config 解析了它,但 poll 循环只用 daemon 级 `poll_interval`——每轮都跑脚本。想省脚本开销就调大 poll_interval |
|
||||
| 5 | `duration`/`decay` 不参与准入 | rusage 语法可解析,当前只进作业指纹/展示 |
|
||||
| 6 | FlagValue.ToJSON 无 external 键 | apiserver JSON 里看不到 EXTERNAL bit;用 `xceadmin config dump` 的 `external=True` 判断 |
|
||||
| 7 | extres status 仅本机 | `xceadmin extres status` 读本机 JSON 文件;多节点时需 ssh 到 xceesd 节点 |
|
||||
| 8 | pending_reason CLI 显示 `-` | CLI 侧 pending reason 展示链有缺口(已知遗留),用 describe/JSON 看 |
|
||||
| 9 | 调度器 stale join | controller 重启后调度器 rejoin 有已知问题,标准流程是调度器随 controller 重启 |
|
||||
| 10 | limits 项目名无校验 | limits.yaml 的 `projects.members` 不做 catalog 校验,拼写错误静默不生效 |
|
||||
|
||||
---
|
||||
|
||||
## 附:快速上手 checklist
|
||||
|
||||
```bash
|
||||
# 1. resources.yaml 声明 extlic(location: [external],无 value)
|
||||
# 2. xceadmin config build && config push
|
||||
# 3. 重启 apiserver + scheduler
|
||||
# 4. 部署 xceesd(esd.yaml)到 license 采集主机,脚本同主机
|
||||
# 5. xceadmin extres status 确认 value 非 "no value yet"
|
||||
# 6. xceadmin config dump 确认 external=True
|
||||
# 7. xce jobs submit -R "rusage[extlic=1]" -- sleep 60 → RUN
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue