跳转到内容

内存: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,要么加内存,而不是在两者之间反复切换。

参考资料 ​

Proxmox VE 非官方中文使用指南,与 Proxmox Server Solutions GmbH 无隶属关系。