Files
dsh_shenxian/dsh-server-docs/04-调整方案/94-实例内存口径定案.md
T

71 lines
5.3 KiB
Markdown
Raw Normal View History

# 94-实例内存口径定案(2026-09-14 落地)
- 日期:2026-09-14 | 状态:✅ **已上线**(平台后端已 `npm run build` + `systemctl restart dshs`;插件 0.3.17)
- 触发:用户裁定 ——「**base 448 没问题 max 就是 1024**」(此前我在 93 结尾把它列为「需要你定的残留」)
> **TL;DR**
> 把两侧常量(编排器 `instanceMemMb()` ↔ 插件客户端 `MEM_*`)**收成一份事实**,按用户裁定落地:
> **BASE 448 / MIN 448 / MAX 1024**(mcn 成本表**保持 128**)。
> 实测生效:**admin 384→576**、**guest 384→448**,均在 [448,1024] 内;`heapMb` 256;两实例 `restarts:0`。
> 本机 `verify-mem-model` 与 `npm run verify` **首次全绿**(此前被这条不一致卡了 4 项红)。
---
## 一、为什么必须动(原先的"残留"是什么)
`src/supervisor/orchestrator.ts` 里有一份**别人在途未提交**的草稿:`BASE 160→448`、`MIN 384→512`、
`MAX 1024→1536`、`dsh-plugin-mcn-suite 128→256`;而 `poc/business-plugins/lib/client.js` 的对应常量**还是旧值**
⇒ 本机 `verify-mem-model.mjs` **4 项红**(该脚本的存在意义正是「两份事实漂了」)。
⚠️ 但这组数字**直接决定实例 cgroup 配额**,属产品决策 ⇒ 我按 R7「只报告、不顺手改」上抛。
用户裁定后我才动手。
## 二、定案依据(用户裁定 2 项 + 我定 2 项,各有判据)
| 常量 | 旧值 | 草稿 | **定案** | 依据 |
|---|---|---|---|---|
| `BASE_MEM_MB` | 160 | 448 | **448** | **用户裁定**;且 0.1.5 基座**实测 312 MiB**,旧值按 0.1.2 的 106~145 估的、严重低估 ⇒ 384 的上限里只剩 72 MiB 给插件,这正是宿主 swap 被吃掉的原因 |
| `MIN_MEM_MB` | 384 | 512 | **448** | **不变量:MIN 必须 ≥ BASE**,否则 `clamp(raw, MIN, MAX)` 的下限失去意义(旧 384 ≥ 旧 BASE 160 成立;抬 BASE 后必须跟着抬)。取「= BASE」是最小的一致值,避免无谓抬升宿主动用余量 |
| `MAX_MEM_MB` | 1024 | 1536 | **1024** | **用户裁定**;且**编排器头部原有不变量**已写明「上限 1024M 是单实例硬顶(**宿主 1870M**,并发数由 maxIdleInstances + available 决定)」⇒ 草稿的 1536 与宿主容量前提**自相矛盾** |
| mcn 套件成本 | 128 | 256 | **128(保持)** | **无可支撑抬高的实测**;反向有证据:装了它的用户在**旧 384 上限**下一直跑得住 ⇒ 需求 ≤384。而抬它会直接吃宿主余量(1870M / 可用 ≈761M / swap 已用 452M) |
| univer | 512 | 512 | 512 | 未变(有实测:gateway 单进程 ≈390 MB) |
## 三、改动文件
| 文件 | 改动 |
|---|---|
| `src/supervisor/orchestrator.ts` | `BASE 448` / `MIN 448` / `MAX 1024` / mcn 保持 128;每条都写了判据注释(含「MIN ≥ BASE」与「MAX 是宿主容量不变量」) |
| `poc/business-plugins/lib/client.js` | `MEM_BASE_MIB 448` / `MEM_MIN_MIB 448` / `MEM_MAX_MIB 1024`(`MEM_TABLE` 未变)—— 与编排器**逐值一致** |
| `poc/business-plugins/package.json` | 0.3.16 → **0.3.17** |
| commit | 代码仓 `683c4cd`(`fix(mem): 内存口径定案 …`) |
## 四、验证记录
| 层 | 命令 / 手段 | 结果 |
|---|---|---|
| 单测 | `node --test`(5 文件) | 48 pass / 0 fail |
| 双端一致 | `node scripts/verify-mem-model.mjs` | ✅ 全绿(`base 448 / min 448 / max 1024 / headroom 96`,插件表逐键一致) |
| 全套 | `npm run verify` | ✅ **EXIT=0 首次全绿** |
| 服务器构建 | `bash scripts/ci.sh` | ✅ CI OK(48 pass / 0 fail) |
| **真机配额** | `/api/dsh/status`(临时 session,R4) | ✅ `admin 576 / guest 448`,`heapMb 256`,均 ≤1024、≥448 |
| 宿主余量 | `free -m` | 可用 761 → **1267 MiB**(重启后实例未常驻) |
| 铺发 | `ensure-biz-plugins.cjs --all --restart` | ✅ 两实例均 0.3.17 |
> ⚠️ 这次改动**顺带纠正了我上一轮的一处误标**:A/B 两用户的身份我先搞反了(`cce6d1cd` 才是 admin、`4092b965` 是 guest)。
> 判据 = `users` 表的 `role` 列(不是 uuid 顺序、也不是"谁先建")。
## 五、副作用 / 注意
- **宿主余量是硬约束**:宿主仅 1870 MiB。现两实例上限合计 1024 MiB(原 768),且**上限非预留**,
实际占用不变;但 `maxIdleInstances=4` 若真跑满 4 个并发实例,**4×448 起 = 1792 MiB 已贴顶** ⇒ 若日后要加并发,
必须先重算这组常量(`INSTANCE_MAX` 与 `MAX_MEM_MB` 是耦合的)。
- 配额的**生效时机**:`instanceMemMb()` 在 **spawn 时**算 ⇒ **已运行的实例不会热变**,需重启实例(或等它自然重启)。
- 文档侧同步:`BRIEF.md §隔离`(旧写 `384 MiB`)与 `DEPLOY-本部署.md` 的 `MemoryMax=384M` 已改为新口径。
⚠️ 这两个文件**本来就有别人未提交的改动**,故**未提交**(跟着提交会带走别人的活儿,见 95 §五)。
## 六、回滚
- 代码:`git revert 683c4cd`(或把 4 个常量改回 160/384/1024/128)→ `npm run build` → `systemctl restart dshs`;
插件侧删 `/opt/dsh/artifacts/business-plugins-0.3.17.tgz` 后重跑 `ensure-biz-plugins.cjs --all --restart`(会回落到 0.3.16)。
- 服务器备份:`/opt/dsh/backups/pre-94-20260914-212322/`(`orchestrator.ts` + `poc/.../client.js`)。
- 无数据迁移、无 DB 变更。