内存口径统一:配额计入堆外余量,展示不再自相矛盾 - #2
Merged
Merged
Conversation
utils.memFootprintMB(xmx) = xmx + max(memOverheadMinMB, xmx × memOverheadPct%), 作为内存折算的唯一入口。本提交只加算子和阈值,不改任何现有行为。 -Xmx 只管堆,而 Metaspace、Code Cache、线程栈、GC 自身结构和 Netty 的 direct buffer 都在堆外 —— MC 服务端的网络层就是 Netty,这块吃得不少。 实测 -Xmx4G 的 Paper 稳定运行 RSS 常在 4.5G 以上,重模组服更多。 余量取百分比与固定下限的较大值:小堆按比例算不够(1G 的 13% 只有 133M, 盖不住 Metaspace+CodeCache+线程栈),大堆按固定值算又不够(模组服 class 多、 direct buffer 大)。 两项进 settings.thresholds,跟 diskWarnPct 一样每部署自己调;同时设 0 即退回纯 Σ-Xmx。settings 用惰性 require —— settings.js 自己 require 了 utils.js,顶层 require 会成环。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PATCH /:iid 在 `mb !== inst.xmx` 判断之前就调 quotaError,而前端保存实例设置时 总会带上 xmx(哪怕用户只改了个名字)。结果是管理员一旦调低某人的配额,该用户 连改个实例名都会 403 —— 而"把内存调小自救"这条唯一的出路,恰好被同一条拦住。 改成只在往上加的时候查配额。持平和缩小是让账变好看的方向,没有理由挡。 这是个独立于配额口径的既有 bug:今天只要管理员调低配额就能触发。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
quotaError 的已用量与本次申请量都过 memFootprintMB。按 Σ-Xmx 把宿主机排满, 实际 RSS 之和一定会超,而超出的部分不会报错:是 OOM killer 半夜随机挑一个 服务端杀掉。沉默的超卖比当场拒绝难查得多。 报错文案把堆和堆外拆开写 —— 合成一个"本次 4608 MB"会让填了 4096 的人 以为面板算错了,而这恰恰是用户第一次撞见这个口径的地方。 usageOf 同步给出 memReservedMB:显示的数必须就是拦人的那个数,否则用户 会看到"2048/4096 还有一半"却被拒,然后去排查一个不存在的 bug。 BREAKING: 已部署面板的租户可用额度会收紧 —— 存量贴着配额的用户升级后即 超额。由上一个提交的"持平/缩小一律放行"兜底,不会有人被锁死,只是不能再 增长。要保持旧口径,把 thresholds 的 memOverheadPct 与 memOverheadMinMB 都设为 0。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
三处展示口径对齐: 内存条:原先 Math.min(100, ram/ramMax*100) 一夹就永久钉在 100%。RSS 超 -Xmx 是常态(堆外开销),于是"健康"和"真要 OOM 了"渲染成同一个样子, 等于把唯一的证据藏了。现在超出部分换琥珀色并标注 `堆外 +N`。 像素风要单独再写一条 —— `.bar i.over` 与 `[data-style="pixel"] .bar i` 特指度都是 (0,2,1),平手时后写的赢,只加前者的话像素风下完全不生效。 宿主机卡:显式读 /proc/meminfo 的 MemAvailable,不再依赖 os.freemem()。 不是 os.freemem() 错,是它不稳定 —— libuv 早期走 sysinfo().freeram(=MemFree, 把可回收 page cache 算作已用),新版改读 MemAvailable。实测 libuv 1.51 上两者 已经一致,但 engines 是 node>=18,同一份代码读到哪个数取决于用户装了哪个 Node。 本机 MemFree 105G 而 MemAvailable 227G,差一百多个 G,不能让它跟着运行时漂。 新增「已承诺」行 = Σ(堆+堆外),也就是配额拦人用的那个数。跟实际用量并排放, 是因为"配额还有余、机器已经满了"这种局面得在总览页看得出来,不用等半夜被 kill。 系统设置页加上两个余量阈值的输入与说明;配额设置页点明内存口径,并写明 "实例卡片内存高于它的 -Xmx 是正常的,不是内存泄漏"。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
smoke 新增 7 条:配额 1024 下 512 的实例恰好放行、1024 的被拦(两条一起才 把边界钉死 —— 只测"被拒"的话余量算成多大都能过)、拒绝文案含"堆外"; 以及存量超额时持平/缩小放行、继续加内存仍被拒的锁死回归。 顺带补 finalizeImportShell():DELETE /:iid 要求 state === 'stopped',而 import 空壳是 'importing',用例建了空壳不 finalize 就删不掉,会让后面的 "删测试用户"因为"该用户还有实例"失败,看起来像权限用例挂了。 README 多租户那行改口径并新增一条说明;ARCHITECTURE 补「内存配额的口径」 一节,以及指标管线里 VmRSS 与 -Xmx 不同口径的说明。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
起因
面板里同时存在三个内存数字,来自三个口径,彼此不换算:
routes/instances.js:284instance.js:1298(VmRSS)os.freemem()routes/host.js:57-Xmx只管堆,RSS 还含 Metaspace、Code Cache、线程栈、GC 自身结构和 Netty 的direct buffer —— MC 服务端网络层就是 Netty。实测
-Xmx4G的 Paper 稳定运行RSS 常在 4.5G 以上,重模组服更多。
按 Σ-Xmx 把宿主机排满,实际 RSS 之和一定会超,而超出的部分不会报错 ——
是 OOM killer 半夜随机挑一个服务端杀掉。沉默的超卖比当场拒绝难查得多。
改了什么
配额计入堆外余量。新增
utils.memFootprintMB()作为唯一折算入口,余量
max(memOverheadMinMB, xmx × memOverheadPct%),默认max(512MB, 13%)(对
-Xmx4G算出 4.52G,与实测的 4.5G+ 吻合)。两项进settings.thresholds,跟
diskWarnPct一样每部署自己调。顺带修一个既有 bug:
PATCH /:iid在mb !== inst.xmx判断之前就调quotaError,而前端保存时总会带上xmx。管理员一旦调低某人配额,该用户连改个实例名都会 403,连"把内存调小自救"都被同一条拦住。改成只在往上加时校验。
这个 bug 今天就存在,不依赖本 PR 的其他改动。
内存条不再假装 100%。原先
Math.min(100, ram/ramMax*100)一夹就永久钉在100%,"健康的堆外开销"和"真要 OOM 了"渲染成同一个样子。现在超出部分换琥珀色
并标注
堆外 +N。宿主机卡改读 MemAvailable,并新增「已承诺」行(Σ 堆+堆外)与实际用量并排。
已部署面板的租户可用额度会收紧 —— 存量贴着配额的用户升级后即超额。
maxMemMB。thresholds.memOverheadPct与memOverheadMinMB都设 0。关于
os.freemem()的一处更正最初的判断是「
os.freemem()在 Linux 上是 MemFree,所以这张卡偏悲观」。实测下来这个说法对现代 Node 不成立:libuv 1.51 / Node 25 上
os.freemem()返回的就是 MemAvailable(本机 MemFree 105G,MemAvailable 227G,os.freemem()= 227G)。改动仍然保留,但理由换成确定性:libuv 早期确实走
sysinfo().freeram,而
engines是node >= 18—— 同一份代码读到哪个数取决于用户装了哪个 Node。显式读
/proc/meminfo才能让口径不随运行时漂移。验证
npm test:73 passed, 0 failed(新增 7 条配额用例)余量算成多大都能过
.over都有视觉区分 ——其中像素风一开始完全不生效(
.bar i.over与[data-style="pixel"] .bar i特指度都是 (0,2,1),平手时后写的赢),已单独补规则
🤖 Generated with Claude Code