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 一律写「远程服务器」。
6.7 KiB
96-实例内存:与插件开关解耦,改为「基础 MIN → 最多 MAX」(2026-09-14 落地)
- 日期:2026-09-14 | 状态:✅ 已上线(平台后端已重建重启;插件 0.3.19 已铺两实例)
- 触发(用户原话,两段):
- 「改为 实例内存不要受插件开关影响,只受 min 和 max 值影响」
- 「改成基础 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;今天早上(1d72e8f09-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 那版的软肋(实测)
- 未知插件按 0 计 ⇒ 装了重插件也不加配额;
- 表本身偏乐观: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.log20:04:53); - 语义混乱:配额随「开关插件」跳动 —— 用户指出「开关插件只是显示给用户看内存占用的预估,怎么会实际影响实例内存」。
二、改了什么
| 层 | 文件 | 改动 |
|---|---|---|
| 后端(权威) | 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 §六 同一处理)。