外观
内存:ballooning、KSM 与 ZFS ARC
「内存不够用」在 PVE 上经常不是真的不够,而是几个内存使用者互相看不见对方:虚拟机自己以为独占了分配的内存,ZFS 的 ARC 缓存默认会尽量多用,KSM 在后台悄悄合并相同页面。这篇把这几个角色理清楚。
先看清楚内存到底花在哪
sh
# 宿主机 shell
free -h
cat /proc/meminfo | grep -i huge
arc_summary | head -20 # 装了 ZFS 才有free -h 里显示"用满了",不代表虚拟机真的用了这么多——ZFS ARC 和内核缓存都算在已用内存里,但会在需要时释放。先分清楚是虚拟机进程本身吃掉的,还是缓存类占用,再决定要不要调。
气球驱动(ballooning):按需伸缩,但有延迟
创建第一个虚拟机已经讲过:填了 Minimum memory 就启用 ballooning,内存在这个区间浮动,由 pvestatd 根据 shares 权重自动分配。这里补充两点它的边界:
| 机制 | 说明 |
|---|---|
| 自动分配触发条件 | 宿主机内存使用率低于某个目标(默认约 80%)时,才会把多余内存分给虚拟机;超过目标就开始回收 |
| shares 权重 | 默认 1000,数值越大在争抢多余内存时分得越多;设为 0 相当于关闭这台虚拟机的自动气球调整 |
| 回收有延迟且需要客户机配合 | 客户机里跑着气球驱动才能响应回收请求,回收不是瞬时的,应付不了内存的瞬时高峰 |
不是所有虚拟机都适合开 ballooning
跑 ZFS 的 NAS 虚拟机、数据库、其他对内存敏感且会自行管理缓存的服务,不适合把内存交给宿主机随时收回——这些应用往往会把大量内存当作自己的缓存来用,一旦被回收,表现为性能骤降而不是优雅降级。这类虚拟机应该给固定内存(Minimum 留空,Ballooning Device 也可以取消勾选)。
Windows 的气球驱动还有额外的性能开销,官方文档建议关键系统不用。
KSM(内核同页合并):省内存,但有安全代价
KSM 在多台虚拟机之间扫描内容相同的内存页,合并成一份物理页,写时复制。多台运行相同操作系统的虚拟机能从中受益——例如十台 Debian 虚拟机的内核和基础库页面大量重复。
PVE 默认全局开启 KSM(ksmtuned 服务)。
| 适用条件 | 代价 |
|---|---|
| 多台虚拟机运行相似的操作系统/软件栈,内存偏紧 | 合并页面依赖内容比对,会占用一些 CPU;更重要的是,共享物理页面存在旁道攻击的理论风险,可能被用来跨虚拟机推测其他租户内存内容里的信息 |
多租户或对外提供服务的场景考虑关闭
如果宿主机上跑着互不信任的租户(例如对外提供的虚拟专用服务器),官方文档建议出于安全考虑关闭 KSM,具体是否需要还要看你所在地区的合规要求。单人或团队自用、虚拟机之间本就互相信任的环境,默认打开没有问题。
- 整机关闭:
systemctl disable --now ksmtuned,再执行echo 2 > /sys/kernel/mm/ksm/run让已合并的页面立即拆开。 - 只给单台虚拟机关闭:
qm set <vmid> --allow-ksm 0(默认是 1)。
ZFS ARC:另一个和虚拟机抢内存的缓存
如果宿主机用了 ZFS(装系统盘、存虚拟机磁盘,或者两者都是),ARC(自适应替换缓存)会缓存最近读取的数据块在内存里,提升后续读取速度。它默认会占用相当大比例的内存,在纯存储服务器上这是好事,但在虚拟化宿主机上会和虚拟机争内存。
给 ARC 设置上限的具体步骤(/etc/modprobe.d/zfs.conf 配置 zfs_arc_max、更新 initramfs、重启生效)见 ZFS 入门。这里只强调调多少的判断依据:
ARC 上限设多少,取决于虚拟机的内存分配总量
给 ARC 留的内存越多,读缓存效果越好,但留给虚拟机(尤其是没开 ballooning 的固定内存虚拟机)的可用内存就越少。经验起点是总内存的 10%–25%,且不低于几个 GB,但更可靠的做法是:算出所有虚拟机的固定内存分配总和,加上宿主机自身需要的内存(建议留至少 1 GiB),剩下的部分才是 ARC 能用的上限。
这项改动需要重启宿主机才能生效——安排到维护窗口。回退方法是把 zfs_arc_max 改回更大的值(或删掉这行配置项使用 ZFS 默认值)并重启。
三者放在一起看
| 机制 | 解决什么 | 什么时候会互相打架 |
|---|---|---|
| Ballooning | 让空闲内存在虚拟机之间动态流转 | 开了 ballooning 的虚拟机数量多、shares 权重没规划时,谁都分不到足够内存 |
| KSM | 合并虚拟机之间重复的内存页,省下物理内存 | 虚拟机操作系统差异很大时收益很小,却仍然产生 CPU 开销 |
| ZFS ARC | 缓存磁盘数据,加速读取 | 不设上限时会和虚拟机的内存分配直接竞争,尤其是内存本就紧张的机器 |
先看整机内存总量是否本来就不够,如果长期贴着上限运行,再多的调优也只是拖延时间,该加内存还是要加。
检查结果
sh
# 宿主机:整体内存使用,能看出还有多少空闲
free -h
# 单台虚拟机的气球状态(Actual 和 Minimum/Maximum 之间的动态值)
qm monitor <vmid>
# 在打开的 monitor 里执行:
info balloon
# KSM 状态和已合并的页面数
systemctl status ksmtuned
cat /sys/kernel/mm/ksm/pages_sharing
# ZFS ARC 当前大小和上限
arc_summary | head -20内存紧张的排查顺序:先看 free -h 里 available 是否真的偏低,再看 ARC 占用是否超出预期,最后看是否有虚拟机的气球设置不合理(该固定内存的开了浮动,或者 shares 权重没按重要程度分配)。
常见问题
改了 zfs_arc_max 没生效。 需要重启宿主机;如果根文件系统在 ZFS 上,还要先执行 update-initramfs -u -k all,否则新的初始化脚本不会带上这个参数。
开了 ballooning 的虚拟机偶尔卡顿。 检查宿主机整体内存是否长期处于紧张状态,导致气球驱动频繁大幅度回收;也检查客户机内部有没有装气球驱动对应的组件(Linux 内置,Windows 需要 VirtIO 驱动包里的 balloon 服务)。
关掉 KSM 之后内存占用明显上升。 属于预期行为——之前被合并省下的内存被重新分开占用。如果内存因此不够用,要么保留 KSM,要么加内存,而不是在两者之间反复切换。