Files
dsh_shenxian/dsh-server-docs/04-调整方案/96-实例配额与插件开关解耦.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

6.7 KiB
Raw Blame History

96-实例内存:与插件开关解耦,改为「基础 MIN → 最多 MAX」(2026-09-14 落地)

  • 日期:2026-09-14 | 状态:✅ 已上线(平台后端已重建重启;插件 0.3.19 已铺两实例)
  • 触发(用户原话,两段):
    1. 「改为 实例内存不要受插件开关影响,只受 min 和 max 值影响」
    2. 「改成基础 min 最大可以浮动到 max」

TL;DR 平台侧 = cgroup 两个参数:MemoryHigh = MIN = 448 MiB(基础/软限,超过即回收·限速) + MemoryMax = MAX = 1024 MiB(上界/硬限,越界 OOM)⇒ 实际占用在两者之间浮动。 与插件开关无关(不再读 profile 的 bundles)。实测两 scope 均 High=448M / Max=1024M。

⚠️ 勘误(同日,用户两次纠正,都记着) ① 我第一版把它写成「固定配额 = 512 MiB(用户裁定)」——两处都不是用户说的: 用户是在界定谁可以影响配额,不是给"固定"背书,更没指定 512(那是我擅自把 MIN 从 448 抬上去的)。 ② 我第二版又写成「只受 MIN/MAX 决定 ⇒ 一律 448」,同样是我自己加的解读; 用户随后明确:基础是 MIN,最多可以浮动到 MAX。 ③ ⚠️ 我还凭记忆编过一条"之前的实现一直是 D(在 min/max 之间按用量浮动)" —— 用 git 查证后不成立:全仓+全历史 grep MemoryHigh = 0;今天早上(1d72e8f 09-14 04:52)的原文是 clamp(BASE 160 + Σ插件表, MIN 384, MAX 1024),cgroup 只给 MemoryMax=<单值>;更早那版是「写死 384」。 教训:不确定的历史事实必须 git 取证,别用"应该/一直"作答。


一、为什么改(两段历史)

时间 设计 结果
更早 MemoryMax 写死 384 guest 启用 univer(gateway ≈390 MB)后撞死 ⇒ cgroup OOM kill 死循环
2026-09-13(档案 81 · R1-④) 配额 = 基准 + Σ(插件内存预估),clamp [MIN, MAX] 修了 univer 那条,但引入三个软肋 ↓
2026-09-14(档案 96) 基础 MIN → 上浮上界 MAX(两个 cgroup 参数),与插件无关 本次

档案 81 那版的软肋(实测)

  1. 未知插件按 0 计 ⇒ 装了重插件也不加配额;
  2. 表本身偏乐观:admin 带 mcn 后峰值 409 MiB,当时上限 384 ⇒ 一分钟内被 cgroup OOM 杀 4 次 (journalctl -k:oom-kill:constraint=CONSTRAINT_MEMCG + oom_memcg=/system.slice/dsh-114801-*.scope), 打出 crash 熔断(/var/log/dsh-crash-breaker.log 20:04:53);
  3. 语义混乱:配额随「开关插件」跳动 —— 用户指出「开关插件只是显示给用户看内存占用的预估,怎么会实际影响实例内存」。

二、改了什么

层 文件 改动
后端(权威) src/supervisor/orchestrator.ts instanceMemMb() → 拆成 instanceBaseMb()(= MIN,Math.max(128, …))与 instanceMaxMb()(= max(base, MAX));sdArgs 改为 -p MemoryHigh=<base>M + -p MemoryMax=<max>M;删除 PLUGIN_MEM_MB 与 BASE_MEM_MB(不再读 profile 的 bundles);quotaInfo() 返回 {baseMb, memMb, heapMb}(memMb = 上界);MIN_MEM_MB = 448 / MAX_MEM_MB = 1024 保持用户裁定值
接口 src/supervisor/spawner.ts quotaInfo?() 的返回类型同步加 baseMb
客户端(显示) poc/business-plugins/lib/client.js quotaOf() 兜底值改为硬顶上界(进度条 100% 基准与「超限」判据同它);事实行改为 「基础 448 MiB → 最多 1024 MiB · V8 堆 256」(新增 i18n mem.base);MEM_TABLE/MEM_BASE_MIB 保留但仅用于预估;MEM_MIN_MIB 注释改为「基础值(MemoryHigh 软限)」
校验 scripts/verify-mem-model.mjs 反回退断言换成新形态:必须有 instanceBaseMb()/instanceMaxMb()、cgroup 必须给 MemoryHigh=base + MemoryMax=max、两访问器函数体内不得读 bundles、客户端 quotaOf() 必须返回上界、mem.base 必须存在;MIN/MAX/HEADROOM 两处仍逐值一致
版本 poc/business-plugins/package.json 0.3.17 → 0.3.18 → 0.3.19

三、验证

层 手段 结果
单测 / 构建 node --test、本机 build/typecheck ✅ 48 pass / 0 fail;✅
本机全链 npm run verify ✅ EXIT=0 全绿
服务器 bash scripts/ci.sh ✅ CI OK(48 pass / 0 fail)
真机接口 临时 session(R4)→ POST /api/dsh/enter + GET /api/dsh/status ✅ 两用户均 {"baseMb":448,"memMb":1024,"heapMb":256}、running:true
内核生效值(最强) systemctl show -p MemoryHigh -p MemoryMax dsh-*.scope ✅ dsh-100002-* 与 dsh-114801-* 均 High=448M / Max=1024M,当前用量 254 / 278 MiB
插件版本 两 profile 的 dependencies ✅ 均 business-plugins-0.3.19.tgz
拼接产物 抓浏览器真正拿到的 bundle 跑 node --check ✅ 语法通过(含新代码)

四、⚠️ 代价 / 注意

  • MemoryHigh 是"开始回收与限速"的软限:实例稳态若长期高于 448 MiB,会频繁触发直接回收(性能下降)而不一定报错 —— 所以「基础 448」是否够用,要看 /var/log/dsh-instance-mem.log 的当前/峰值(当前 254–278 MiB,正常)。
  • 装重插件(dsh-univer-office,gateway ≈390 MB + 基座 ≈312)会长期超过基础:此时它会靠上浮到 1024 才能活; 若峰值逼近 1024 仍会 OOM ⇒ 那时该抬的是 MIN 或 MAX(用户定),不再靠插件表。
  • 宿主 1870M:maxIdleInstances=4 × Max 1024 = 4096M 远超宿主 ⇒ 并发上限仍受宿主约束(上限非预留,但真跑满会换页)。

五、回滚

  • 代码:git revert <本次 commit>(或把 sdArgs 还原成单个 MemoryMax=<值>)→ npm run build → systemctl restart dshs; 插件侧删 /opt/dsh/artifacts/business-plugins-0.3.19.tgz 再跑 ensure-biz-plugins.cjs --all --restart。
  • 服务器备份:/opt/dsh/backups/pre-97-20260914-222146/(orchestrator.ts / spawner.ts / verify-mem-model.mjs)。
  • 无数据迁移、无 DB 变更。

六、文档口径收敛(同批做的)

BRIEF.md §隔离、DEPLOY-本部署.md(systemd-run 行)、skills/dsh-instance-diagnose(配额单元格 + 诊断命令示例)、 skills/dsh-change-workflow(配置风险 / cgroup 描述 / 并发上限三处)全部改为「基础 448 → 上界 1024(MemoryHigh/MemoryMax)」。 ⚠️ BRIEF.md 与 DEPLOY-本部署.md 本就有别人未提交的改动,故未提交(与档案 95 §六 同一处理)。