低配服务器用 zram 换内存实战:zstd 压缩比查看、swappiness 为何要调到 100 与三个常见坑位

小内存服务器的困境:Swap 一开就卡,不开就 OOM

个人站长最常见的机型是 1GB 或 2GB 内存的轻量服务器。这种配置跑 Nginx + PHP + MySQL 会非常紧张:不开 Swap,内存一满 OOM Killer 直接杀进程,网站 502;开了 Swap,一旦真的换出到磁盘,SSD 上的随机读写能把响应时间从几毫秒拉到几百毫秒,用户体验比 502 还难受。

zram 提供了一条中间路线:在内存里划出一块空间做压缩交换区。换出的页不是写磁盘,而是压缩后留在 RAM 中。由于文本、日志、代码段这类内容压缩率普遍在 2:1 到 4:1,1GB 的物理内存能换来 2-3GB 的"等效交换空间"。代价是 CPU 要多做压缩解压运算——而绝大多数小服务器的 CPU 恰恰是空闲的。

zram 与普通 Swap 的本质区别

普通 Swap 是"把内存页搬到磁盘",本质是用存储换内存,代价是 I/O 延迟。zram 是"把内存页压缩后留在内存",本质是用CPU 换内存,代价只是几微秒的压缩耗时。对低配机器来说,这个交换极其划算。

判断标准也很明确:如果你的 CPU 长期低于 30% 而内存经常吃紧,zram 几乎是免费的容量;反之如果是计算密集型的编译机、转码机,CPU 已经打满,那加 zram 只会让所有任务一起变慢。

方案一:发行版原生 zram(推荐,最省事)

Debian 11/12 和 Ubuntu 20.04 之后都有官方 zram-tools 包,装完改一行配置即可:

apt-get update && apt-get install -y zram-tools

# 编辑配置:/etc/default/zramswap
cat > /etc/default/zramswap <<'EOF'
# 使用多少比例的内存做 zram(这里是 50%)
ALGO=zstd
PERCENT=50
# 优先级高于磁盘 swap
PRIORITY=100
EOF

systemctl restart zramswap
systemctl enable zramswap

压缩算法选择上有讲究:lz4 速度最快、压缩率最低;zstd 压缩率好、CPU 开销适中;lzo-rle 是折中项。对 1-2GB 的小机器,推荐 zstd,因为内存容量比 CPU 时间更稀缺。

PERCENT=50 的含义要理解清楚:它是"按内存比例决定 zram 设备大小"。设成 50 表示创建 512MB 的 zram 设备(1GB 机器),但因为内容被压缩,实际能装下的原始数据通常超过 1GB。不要设成 100——zram 设备本身占用的内存加上压缩开销,设太大会挤压正常业务内存。

方案二:手动创建 zram(可控性更强)

如果不想装额外包,或者需要多设备、按 CPU 核数分配,用 zramctl 手动管理:

# 加载模块(并设置开机加载)
modprobe zram
echo zram > /etc/modules-load.d/zram.conf

# 创建 1 个 zram 设备,大小 768MB,算法 zstd
zramctl --find --size 768M --algorithm zstd
# 输出示例:/dev/zram0

# 格式化为 swap 并启用,优先级设为 100
mkswap /dev/zram0
swapon -p 100 /dev/zram0

# 确认生效
zramctl
swapon --show

如果你希望重启后自动恢复,写一个 systemd 单元而不是塞进 /etc/rc.local

cat > /etc/systemd/system/zram-swap.service <<'EOF'
[Unit]
Description=Setup zram swap
After=multi-user.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'modprobe zram && zramctl --find --size 768M --algorithm zstd && mkswap /dev/zram0 && swapon -p 100 /dev/zram0'
ExecStop=/bin/bash -c 'swapoff /dev/zram0 && zramctl reset /dev/zram0'

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now zram-swap

关键参数:vm.swappiness 怎么设

这是最容易被误解的参数。vm.swappiness 取值范围 0-100,表示内核有多倾向于换出匿名页。默认 60,意思是"内存压力不大时也会适度换出"。

# 查看当前值
cat /proc/sys/vm/swappiness

# zram 场景推荐:调高到 100 甚至 150(是的,可以超过 100)
sysctl -w vm.swappiness=100

# 永久生效
echo 'vm.swappiness = 100' > /etc/sysctl.d/95-zram.conf
sysctl --system

为什么用了 zram 反而要把 swappiness 调?因为传统建议"swappiness 调低"的前提是 swap 在磁盘上,换出代价高昂。而 zram 的交换代价极低,主动把冷数据压缩进 zram,反而能给热数据腾出更多物理内存。这就是常说的"把内存当缓存用"的思路。很多教程照搬"swappiness=10"的老建议,在 zram 场景下是反向优化。

一次 1GB 机器的真实改造过程

有一台 1GB 内存的轻量服务器,跑一个 WordPress 站点加一个静态论坛,平时内存占用在 850MB 上下浮动,几乎贴着上限跑。每到凌晨的备份窗口,内存压力骤增,OOM Killer 就会随机杀掉 PHP-FPM 的子进程,用户第二天早上看到的是零星的 502 记录。

改造思路是这样的。先确认 CPU 长期在 10% 以下——这满足了"用 CPU 换内存"的前提。然后安装 zram-tools,设 PERCENT=60(即 600MB 的 zram 设备)、算法用 zstd、优先级 100。最后把 vm.swappiness 从默认 60 提到 100,让内核放心地把冷数据压进 zram。

改造后的实际数据:zramctl 显示 DATA 约 520MB、TOTAL 约 180MB,压缩比接近 3:1。也就是说,520MB 的冷数据只花了 180MB 的真实内存,等于凭空多出来 340MB 可用空间。OOM 记录从此再没出现过,而 CPU 占用只上升了三个百分点。

这个案例里有个细节值得注意:zram 装下的内容主要是 PHP 的匿名页和一些长期不活跃的缓存,这些数据热度和访问频率都很低,压缩代价小、收益大。反过来,如果这台机器跑的是图片处理或者视频转码,页内容本身就不可压缩,改造效果会差很多。所以判断"要不要上 zram",本质上先要判断"你的内存里装的是什么"。

还有一个容易忽视的收益:zram 让服务器不再依赖磁盘 swap。这意味着你可以在云控制台把磁盘降配到更小的容量,一年下来省下的钱足够再买一台小机器。对注重成本的个人站长来说,这是个能算清楚的账。

实践中的三个坑

坑一:zram 和磁盘 swap 优先级设置不当。必须让 zram 的 pri 高于磁盘 swap(比如 zram=100,磁盘=10),否则内核会优先使用慢的磁盘 swap,zram 形同虚设。用 swapon --show 确认两行的 PRIO 值。

坑二:把 zram 大小设得比内存还大。有些教程说"1GB 内存可以设 2GB zram",这在理论压缩率上成立,但一旦数据不可压缩(比如已经被压缩过的图片、加密文件),zram 会占满真实内存,触发 OOM。稳妥值是物理内存的 50%-75%。

坑三:zram 里的数据不持久。重启后 zram 内容全部丢失,这是设计使然。如果里面有数据库的脏页没来得及刷盘,可能造成数据不一致。所以跑数据库的机器,要么把 swappiness 调回较低值,要么给 MySQL 单独限制内存,避免它把 buffer pool 挤进 zram。

怎么验证 zram 真的在工作

# 查看压缩率、原始数据量、实际占用内存
zramctl
# NAME    ALGORITHM  DISKSIZE  DATA  COMPR  TOTAL
# /dev/zram0  zstd    768M     412M  2.9:1  158M

# DATA=压缩前的数据量,TOTAL=实际占用的物理内存
# 上例表示:装了 412MB 数据,只花了 158MB 物理内存

# 看换入换出速率(si/so),单位 KB/s
vmstat 2 5
# si 和 so 持续为正但不大,说明 zram 在正常吸收冷页

# 看内存总体状况
free -h
# Swap 那一行显示总容量和已用量,已用量包含 zram 内容

判断 zram 是否划算,看 COMPR 列:压缩比在 2:1 以上就值得用,接近 1:1 说明你的数据本来就不可压缩(比如纯图片、纯二进制),这时候 zram 只是在浪费 CPU。

什么情况下不要用 zram

  • 内存 ≥ 8GB 且负载稳定:内存本来就富余,加 zram 没有收益,反而增加 CPU 开销。
  • CPU 是瓶颈:已经有高负载的编译、转码任务,压缩解压会加剧争抢。
  • 数据不可压缩为主:纯图床、纯文件存储服务器,压缩率低,不划算。
  • 有严格延迟要求:虽然 zram 比磁盘 swap 快得多,但仍有微秒级抖动,对极致稳定的场景不如直接加内存。

总结

zram 解决的核心矛盾是"低配服务器买不起内存,但 CPU 有余量"。它把 Swap 从"存储换内存"改成"CPU 换内存",在 1-2GB 的小机器上通常能换来 2-3 倍的等效内存容量。落地要点就四条:用 zstd 算法、大小取物理内存的 50%-75%、优先级高于磁盘 swap、swappiness 调到 100。

但别忘了它只是缓解手段。真正的容量规划还是要看业务增长趋势——如果 zram 长期处于高占用、压缩比却在下降,那说明内存缺口已经超过了压缩能弥补的范围,该考虑升级配置或者把数据库拆到独立机器了。运维工具的价值在于给你争取时间,而不是替代正确的架构决策。

最后补充一个判断节奏的建议:上 zram 之后,最好连续观察两周的 zramctl 输出,重点看 COMPR 这一列的走势。如果压缩比稳定在 2.5:1 以上且 DATA 没有持续突破设备容量,说明当前配置是健康的;如果压缩比掉到 1.5:1 附近,或者 DATA 长期顶着 DISKSIZE 的上限,那说明内存确实已经不够用了,压缩只是把 OOM 的时间点往后推了推。这个观察成本很低——一条命令、两秒钟,但它能让你在真正出事之前就做出决策,而不是等到某天凌晨被 OOM 叫醒。

Last modification:September 24th, 2026 at 10:24 pm

Leave a Comment