? 开篇故事
某天我登上一台刚装好的 PVE 节点,准备美滋滋地部署几个 LXC 容器。一个 free -h 下去,直接愣住了:
total used free
Mem: 31Gi 24Gi 6.6Gi等等?31GB 内存,用了 24GB? 我 VM 和 CT 加起来还不到 4GB 啊,剩下的 20GB 谁吃了?
再一看——ZFS ARC 占了 15GB。好家伙,系统自己就干掉了半台机器的内存。
这不是 bug,也不是中毒,是 ZFS 的 ARC(自适应替换缓存) 在干活。这篇文章就把这件事彻底讲清楚。
? ARC 是什么?ZFS 为什么这么能吃?
传统文件系统 vs ZFS
| 特性 | 传统文件系统(ext4/xfs) | ZFS |
|---|---|---|
| 缓存机制 | Page Cache(内核管) | ARC(ZFS 自己管) |
| 缓存上限 | 系统自动调节 | 默认占物理内存的 50% |
| 缓存内容 | 文件数据 | 文件数据 + 元数据 + 压缩表 + 去重表 |
| 缓存能效 | 一般 | 极高(COW 特性加成) |
| 开箱即用 | 省心 | "我全都要"模式 |
ZFS 的哲学是:闲着也是闲着,不如把内存拿来当缓存。因为 ZFS 是 Copy-on-Write(写时复制)文件系统,对缓存的需求天然比传统文件系统高——多一层缓存就少一层磁盘 IO,性能差距非常明显。
ARC 默认吃多少?
ARC 上限 = 物理内存 × 50%
我的 31GB 机器 → 15.5GB 归 ARC。如果是 64GB → 32GB 归 ARC。128GB → 64GB 归 ARC。
数据越热(经常读写),ARC 越膨胀。数据越冷(没人访问),ARC 自动收缩还给系统。
? ARC 到底缓存了啥?
| 缓存内容 | 占比 | 说明 |
|---|---|---|
| 文件数据 | 最大头 | 你读写过的 VM/CT 磁盘文件 |
| 元数据 | 少量 | 目录结构、文件属性、ZAP 对象 |
| 压缩缓存 | 看情况 | 压缩后的数据块(LZ4/ZSTD) |
| 去重表(DDT) | 启用去重才用 | 一般不启用 |
这也是为什么 ZFS 吃内存比传统文件系统狠——它缓存的不只是"文件内容"。
?️ 怎么看 ARC 吃了多少?
几个命令干活:
# 看 ARC 总大小和命中率
arcstat 1 3
# 或直接看 /proc/spl/kstat/zfs/arcstats
cat /proc/spl/kstat/zfs/arcstats | grep -E "^(size|c|hits|misses)"arcstat 输出示例:
time read miss miss% dmis dmizm pmis pmism dds dds% size c
12:00 3.2K 12 0.4% 12 0.0% 0 0.0% 0 0 14G 15G重点看:
• size:当前 ARC 占了多少内存(14G)
• c:ARC 上限(15G),接近上限说明满负荷
• miss%:缓存未命中率,越低越好(通常 < 5%)
⚠️ 什么时候需要手动管?
ARC 不是吃白饭的——系统内存紧张时,ARC 会自动释放。但有些场景它"自动"得不够快:
| 场景 | 表现 | 建议 |
|---|---|---|
| VM/CT 少(2-3 个) | ARC 占 50%,纯浪费 | 手动限制到 20-30% |
| 机器内存小(8-16GB) | ARC + VM 抢内存 | 限制到 2-4GB |
| 需要跑数据库/高负载应用 | VM 内应用卡顿 | 限制到 2-4GB,留给应用 |
| 大内存 + 大量 VM(64GB+) | ARC 物尽其用 | 不用管,默认 50% 很合理 |
| ZFS 作为主存储 + 大量 IO | ARC 越高越快 | 甚至可以上调到 70-80% |
一条金线:VM/CT 分配的总内存 + ARC 上限 ≤ 物理内存 × 0.9,留 10% 给系统和突发。
? 三种限制 ARC 的方法
方法一:热写入(即时生效,重启失效)
最适合临时调整,不想重启节点:
# 立即将 ARC 上限设为 8GB(单位:字节)
echo "8589934592" > /sys/module/zfs/parameters/zfs_arc_max
# 验证
cat /sys/module/zfs/parameters/zfs_arc_max效果立竿见影——ARC 会立刻开始回收,把内存还给系统。适合"先试试 8GB 够不够用"的场景。
我的案例:从 15GB 限到 8GB,free -h 立马释放 7GB,VM 一个都没重启。
方法二:modprobe.d 持久化(需重启)
想永久生效,写入配置文件:
# 写入持久化配置
echo "options zfs zfs_arc_max=8589934592" >> /etc/modprobe.d/zfs.conf
# 重启后生效
reboot适合"确定 8GB 够用"后一次性搞定。
方法三:不限制(默认)
什么都不做也行。ZFS 的 ARC 是可回收缓存——内核内存紧张时系统会自动触发回收,优先级比应用内存低。
唯一的代价是:回收需要时间。如果你突然启动一个吃内存的大 VM,系统得先等 ARC 腾出空间,启动会比平时慢几秒。
? 真实案例
我的一台 PVE 节点(31GB 内存):
| 阶段 | ARC 占用 | 可用内存 | VM/CT 数 | 负载表现 |
|---|---|---|---|---|
| 默认(未限制) | 15GB | 6.6GB | 8 个 | 偶尔卡顿 |
| 限制到 8GB | 7.8GB | 13.5GB | 8 个 | 丝滑流畅 |
| 限制到 4GB | 3.9GB | 16GB | 8 个 | 丝滑,IO 无明显下降 |
结论:8GB ARC 对大多数 Homelab 场景绰绰有余。即使我从 15GB 砍到 8GB,ARC 命中率从 99.7% 掉到 99.5%——几乎没区别。
? 写在最后
ZFS 吃内存不是 bug,是特性。它默认的"我全都要"策略在服务器场景很合理——内存不用来缓存就是浪费。但在 Homelab 里,16-32GB 的机器上被 ARC 吃掉一半,确实会让人心跳加速。
我的建议:
• 装完先看:
arcstat看看 ARC 实际占了多少• 够用就别动:VM 运行顺畅就没必要管
• 不够再限:热写入
zfs_arc_max试个舒服的值,再决定要不要持久化
搞定这些,你的 PVE 就不会"开机就吃掉半条命"了 ?
? 相关命令
| 命令 | 作用 |
|---|---|
arcstat 1 3 | 实时监控 ARC 命中率 |
cat /proc/spl/kstat/zfs/arcstats | 查看 ARC 详细统计 |
echo N > /sys/module/zfs/parameters/zfs_arc_max | 热修改 ARC 上限 |
cat /sys/module/zfs/parameters/zfs_arc_max | 查看当前 ARC 上限 |
free -h | 查看系统内存使用 |
本文链接:https://www.kinber.cn/post/6584.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:

支付宝微信扫一扫,打赏作者吧~
