WeKan RAM 高用量监控设计:系统内存与 Swap 压力如何进入管理面板 Problems 报告
【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekan
这篇技术文章围绕 WeKan 的设计文档 RAM-usage.md 展开:讲清"管理面板 → Problems → RAM usage"监控子系统的完整设计——系统级 RAM/Swap 采样、基于滞回(hysteresis)的 episode 状态机、"每期事件只记 start/end 两行"的报告机制与全部 7 个环境变量。读完你可以掌握该设计的测量原理与防抖动参数,并能对照仓库中已实现的 CPU 监控源码(server/lib/cpuMonitor.js、models/lib/cpuHighTracker.js)理解三个 Problems 监控(CPU/RAM/Disk)共享的同一套架构。
设计定位:与 CPU、Disk 监控同族的"观察者"
WeKan 与 FerretDB 部署在同一台机器时,两者合计占用的内存可能把主机推入 swap,结果是其他软件被"饿死"或直接崩溃,而一旦开始换页,整机速度都会显著下降。RAM 监控子系统的职责就是监视系统级内存 + swap 用量,并为每段持续的高用量时期只在Admin Panel → Problems → RAM usage报告中记录开始与结束两行,让运维能直接看到:内存压力从何时开始、峰值有多严重、何时缓解——同时避免报告被海量行刷屏。
需要明确当前状态:该文档标注为 **Status: Design (proposed)(提议中的设计),其"Related (to be added)"清单里的server/lib/ramMonitor.js、server/lib/cpuLog.js对应物server/lib/ramLog.js、models/lib/ramHighTracker.js在当前仓库中尚未落地**。这一点可以从仓库代码得到印证:
- 事件流注册表 models/eventLog.js 目前是
EVENT_STREAMS = ['security', 'speed', 'tests', 'cpu', 'database', 'integrity']——cpu流已注册,ram流尚未加入; - server/lib/cpuMonitor.js 与 models/lib/cpuHighTracker.js 是已实现的 CPU 姊妹模块,RAM 设计刻意复用它们的形状。
它属于 Problems 面板 家族的一员,与已实现的 CPU-usage 和 Disk-usage 监控共享同一形态、同一事件流机制和同一报告模板。
需求清单
设计文档列出了 5 条硬性需求,它们是整篇文章展开的骨架:
- 持续监视 RAM 与 swap:在 WeKan(以及并存的 FerretDB)运行期间,持续观察系统 RAM 和 swap 的占用情况;
- 新增报告入口:Admin Panel → Problems → RAM usage;
- 只记 start 与 end:每段高用量时期只产生两行(高用量开始 / 高用量结束),保证报告永不刷屏;
- 每行记录完整画像:该行使用的 RAM 与 swap(已用/总量及百分比)、该时期的峰值、持续时间,以及事发时 WeKan/FerretDB 在做什么(与 CPU 监控相同的粗粒度 activity 标签);
- 尽力而为、绝不抛异常:在数字不可用的环境(如没有
/proc/meminfo的沙箱)中降级为 no-op,不影响主流程。
测量设计:系统级口径,天然包含 FerretDB
RAM 监控器(设计为server/lib/ramMonitor.js)按固定间隔采样,间隔由WEKAN_RAM_SAMPLE_INTERVAL_MS控制,默认 5 秒。两部分测量口径如下:
RAM(操作系统级)
- 用
os.totalmem()与os.freemem()获取系统总内存与空闲字节数; - 已用 RAM 百分比 =
(total − free) / total × 100; - 关键在于测量发生在 OS 层,因此把 WeKan、FerretDB 和机器上所有其他进程都算进去——这正是"机器是不是快没内存了"的真实信号,而不是 WeKan 进程自己的视角。
Swap(Linux)
- 读取
/proc/meminfo中的SwapTotal与SwapFree; - 已用 swap 百分比 =
(SwapTotal − SwapFree) / SwapTotal × 100; - 当
/proc/meminfo不可读或系统根本没有配置 swap 时,swap 报告为"不可用",此时仅由 RAM 驱动 episode 判定。
一个重要的边界:Node 的process.memoryUsage()(即 WeKan 自身的 RSS)只作为 detail 里的上下文信息记录,不是触发条件——触发条件永远是系统级的内存/Swap 占用。这与 CPU 侧的口径完全一致:已实现的 server/lib/cpuMonitor.js 同样强调"从os.cpus()的 idle/total 差值测量系统级 CPU%,因此包含 WeKan、FerretDB 和所有其他进程——这正是我们关心的'机器是否过载'信号"。
Episode 状态机:用滞回防止 flapping
设计将"采样流 → 事件"的转换交给一个纯函数、可单测的状态机(设计文件为models/lib/ramHighTracker.js),它与已实现的 models/lib/cpuHighTracker.js 形状完全相同。以仓库中已落地的HighCpuTracker为例,可以精确理解这套状态机的实现模式:
- 构造时接受
highPct/lowPct/enterSamples/exitSamples四个参数(见 cpuHighTracker.js#L13-L24); update(pct, now)每喂入一个采样就返回三种结果之一:高用量开始的{ event: 'start', at, pct }、高用量结束的{ event: 'end', at, startedAt, durationMs, peak }、或无事件的{ event: null }(见 cpuHighTracker.js#L30-L55);- 进入高态:连续
enterSamples次采样 ≥highPct;退出高态:连续exitSamples次采样 <lowPct,期间持续刷新peak; - 文件头注释明确说明了设计意图:把
lowPct < highPct的滞回用于防止"数值在阈值附近抖动时 start/end/start/end 反复闪报"(no-flap hysteresis)。
RAM 版本在此形状上加入双指标判定:
- 进入高态:连续
WEKAN_RAM_HIGH_SAMPLES(3)次采样满足RAM 已用 ≥WEKAN_RAM_HIGH_PERCENT(默认 90%) 或 swap 已用 ≥WEKAN_SWAP_HIGH_PERCENT(默认 25%)任一条件。25% 的 swap 阈值背后是一个工程判断——任何真实的换页本身就已经是性能问题了; - 退出高态:连续
WEKAN_RAM_LOW_SAMPLES(3)次采样中 RAM 已用 <WEKAN_RAM_LOW_PERCENT(默认 80%)且swap 低于 swap 阈值; - 峰值追踪:episode 期间记录遇到的最高 RAM% 与最高 swap%,供结束行使用。
滞回区间(90% 进 / 80% 出)与"连续 3 次"的要求,意味着单次毛刺采样不会产出一行报告——这与 CPU 侧 85% 进 / 70% 出的策略同构。
报告:每期事件恰两行,自描述的 start → end 记录
episode 写入eventLog集合,走ram流——一个与cpu并列的新事件流(文档称其为 "a newsecurityCategories-style stream alongsidecpu"),由现有的通用eventStreamReport模板展示:分页、可搜索、只读。CPU 侧这条管道在 models/eventLog.js 的EVENT_STREAMS注册中已可验证,RAM 报告接入后将以同样的stream="ram"方式复用eventLogPage数据方法。
每期事件正好两行,文档给出了标准行格式:
- start(
detected状态):high RAM usage started (>= 90%): RAM 7.4/8.0 GB (92%), swap 0.6/2.0 GB (30%), load …, WeKan: <activity> - end(
remediated状态):high RAM usage ended after 42s (peak RAM 96%, peak swap 41%, back under 80%): RAM 5.1/8.0 GB (64%), swap 0.1/2.0 GB (5%)
注意 end 行携带了持续时间、RAM/Swap 峰值、恢复后的当前值,start 行则携带WeKan: <activity>标签——长操作像 CPU 侧那样通过setActivity('…')登记粗粒度活动名,使报告能回答"内存飙升时 WeKan 在干什么"。
严重度分级规则:当 RAM 峰值 ≥ 95% 或 swap 正在被使用时记为high,否则medium。
环境变量(完整参数表)
设计文档给出 7 个可覆写的环境变量,以下是原表(默认值与设计语义):
| 变量 | 默认值 | 含义 |
|---|---|---|
WEKAN_RAM_MONITOR | true | 总开关 |
WEKAN_RAM_SAMPLE_INTERVAL_MS | 5000 | 采样间隔(毫秒) |
WEKAN_RAM_HIGH_PERCENT | 90 | RAM 已用百分比达到/超过此值时进入高态 |
WEKAN_RAM_LOW_PERCENT | 80 | RAM 已用百分比低于此值时退出高态 |
WEKAN_SWAP_HIGH_PERCENT | 25 | swap 已用百分比达到/超过此值时也进入高态 |
WEKAN_RAM_HIGH_SAMPLES | 3 | 进入高态所需的连续高采样次数 |
WEKAN_RAM_LOW_SAMPLES | 3 | 退出高态所需的连续低采样次数 |
从源码结构看,这些参数将沿用 CPU 监控已验证的解析模式:server/lib/cpuMonitor.js#L21-L48 用统一的intEnv(name, fallback)帮助函数解析整数环境变量(非法值回退默认值),总开关则用String(process.env.WEKAN_CPU_MONITOR || 'true').toLowerCase() !== 'false'判定——只有显式设为false才关闭。
测试策略与工程约束
设计文档对工程质量提出了两条明确约束:
- 纯函数单测,不依赖 Meteor:tracker 状态机与
/proc/meminfo解析器都是纯函数,与cpuHighTracker.js及其测试(tests/cpuHighTracker.test.cjs)做法相同,在正例与反例中覆盖进入/退出滞回,以及 meminfo 解析的边界情况(文件缺失、swap 为零/未配置)。 - observe-and-report only(只观察上报,不做治理):这是 RAM 监控与 CPU 监控最本质的差异。CPU 侧有 governor——
isHighCpu()/pauseIfBusy()让批量操作在系统繁忙时让出 CPU,还可以向 FerretDB 发出跨进程降速请求;而 WeKan无法安全地"按需释放"RAM,所以 RAM 侧没有 governor,其价值完全在于可见性:一条自描述的 start → end 记录,让运维据此去扩容宿主机内存或限制并发。设计文档特意指向 CPU-usage(带治理的姊妹设计)与 Disk-usage(磁盘姊妹设计)作为对照阅读。
与已实现 CPU 子系统的对照:该设计可信的依据
由于 RAM 模块本身尚属"proposed",评估其设计合理性最好的依据,就是仓库中已实现的同族代码:
| 设计要素 | RAM 设计(待实现) | CPU 实现(已验证,可引用) |
|---|---|---|
| 采样器 | server/lib/ramMonitor.js(OS 级 RAM + swap) | server/lib/cpuMonitor.js,os.cpus()差值 + 5s 间隔 |
| 状态机 | models/lib/ramHighTracker.js(RAM 或 swap 双条件) | models/lib/cpuHighTracker.js,单条件HighCpuTracker |
| 事件流 | eventLog的ram流 | EVENT_STREAMS中的cpu,见 models/eventLog.js |
| 报告 | eventStreamReport,stream="ram" | eventStreamReport,stream="cpu",分页/搜索/只读 |
| 行式约束 | 每期恰 2 行(start/end) | 每期最多 3 行(start / mitigation / end) |
| 测试 | tracker + meminfo 解析纯函数单测 | tests/cpuHighTracker.test.cjs、tests/cpuMonitorWiring.test.cjs |
CPU 侧还有一个 RAM 设计有意省略的部分:CPU 的 end 行会汇报"降速是否真的起效"(After slowing down, CPU went A% → B%),因为 CPU 有治理动作可汇报;RAM 没有这个维度——再次印证"只观察、不治理"的定位。
适用前提与限制
- 平台:Swap 测量依赖 Linux 的
/proc/meminfo,非 Linux 或未挂载该文件的环境(如部分沙箱)中 swap 显示为不可用,episode 仅由 RAM 驱动;整体行为为 best-effort,数字不可用时降级为 no-op,不抛异常。 - 采样成本:默认 5 秒一次,两次纯内存读取(
os.totalmem/os.freemem加一次/proc/meminfo读取),开销极低;但"3 次连续采样"的滞回意味着最坏情况下高态判定延迟约一个间隔周期(默认 15 秒),这是防抖动换取的响应延迟。 - 报告语义:
remediated状态表示"高用量时期结束"而非"WeKan 修复了某问题"——对 RAM 而言缓解只能来自外部(负载回落、扩容),这正是设计文档要求记录峰值与持续时间的目的:给运维提供扩容或限并发的决策依据。
相关文档与源码索引
- 设计文档:docs/Features/Admin-Panel/Problems/RAM-usage.md
- 姊妹设计:CPU-usage、Disk-usage、Problems 面板总览
- 已实现的对照源码:server/lib/cpuMonitor.js、models/lib/cpuHighTracker.js、models/eventLog.js、server/lib/cpuLog.js
- 参考测试:tests/cpuHighTracker.test.cjs、tests/cpuMonitorWiring.test.cjs
【免费下载链接】wekanThe Open Source kanban, built with Meteor. GitHub issues/PRs are only for FLOSS Developers, not for support, support is at https://wekan.fi/commercial-support/ . PR source translation to imports/i18n/data/en.i18n.json, other translations at https://app.transifex.com/wekan/wekan项目地址: https://gitcode.com/GitHub_Trending/we/wekan
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考