ZRAM 全自动全功能优化脚本 (Debian/Alpine 通用)

在安装脚本中加入碎片整理后台自动优化

我已经将系统探测、zram 安装、内核神油优化、碎片整理、以及 Crontab 自动维护任务全部整合到了这一个脚本中。

:rocket: ZRAM 全自动全功能优化脚本 (Debian/Alpine 通用)

Bash

#!/bin/bash
# ZRAM 一键安装、内核优化与自动维护脚本

# 1. 权限检查
[ "$(id -u)" -ne 0 ] && echo "错误: 请以 root 权限运行" && exit 1

echo "--- 1. 正在识别系统环境 ---"
if [ -f /etc/alpine-release ]; then
    OS="alpine"
    echo "系统: Alpine Linux"
elif [ -f /etc/debian_version ]; then
    OS="debian"
    echo "系统: Debian/Ubuntu"
else
    echo "错误: 暂不支持此系统" && exit 1
fi

# 2. 计算推荐大小 (物理内存的 100%)
TOTAL_MEM=$(free -m | grep Mem | awk '{print $2}')
ZRAM_SIZE="${TOTAL_MEM}M"

# 3. 探测最优算法
modprobe zram 2>/dev/null
BEST_ALGO="lzo"
[ -f /sys/block/zram0/comp_algorithm ] && ALGOS=$(cat /sys/block/zram0/comp_algorithm)
for a in zstd lz4 lzo-rle; do
    echo "$ALGOS" | grep -q "$a" && BEST_ALGO=$a && break
done

echo "方案: 大小=$ZRAM_SIZE, 算法=$BEST_ALGO"

# 4. 执行系统特定安装
if [ "$OS" = "alpine" ]; then
    apk add zram-init util-linux bash
    cat << EOF > /etc/conf.d/zram-init
num_devices=1
type0=swap
algo0=$BEST_ALGO
size0=${TOTAL_MEM}
EOF
    rc-update add zram-init default
    rc-service zram-init restart
else
    apt-get update && apt-get install -y util-linux
    cat << EOF > /usr/local/bin/zram-start.sh
#!/bin/bash
swapoff /dev/zram0 2>/dev/null
echo 1 > /sys/block/zram0/reset 2>/dev/null
echo $BEST_ALGO > /sys/block/zram0/comp_algorithm
echo $ZRAM_SIZE > /sys/block/zram0/disksize
mkswap /dev/zram0
swapon -p 100 /dev/zram0
EOF
    chmod +x /usr/local/bin/zram-start.sh
    cat << EOF > /etc/systemd/system/zram.service
[Unit]
Description=ZRAM Optimized Swap
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/zram-start.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
    systemctl daemon-reload
    systemctl enable zram
    systemctl restart zram
fi

echo "--- 2. 应用内核神油优化 ---"
# 立即生效
sysctl -w vm.swappiness=100
sysctl -w vm.page-cluster=4
# 永久生效
sed -i '/vm.swappiness/d' /etc/sysctl.conf
sed -i '/vm.page-cluster/d' /etc/sysctl.conf
echo "vm.swappiness=100" >> /etc/sysctl.conf
echo "vm.page-cluster=4" >> /etc/sysctl.conf

echo "--- 3. 配置自动碎片整理任务 ---"
# 1. 确保维护脚本存在
cat << 'EOF' > /usr/local/bin/zram-optimize.sh
#!/bin/bash
if [ -f /sys/block/zram0/compact ]; then
    echo 1 > /sys/block/zram0/compact
    echo "[$(date)] ZRAM 碎片整理已完成"
fi
EOF
chmod +x /usr/local/bin/zram-optimize.sh

# 2. 修复 Alpine 的 Crontab 目录问题并写入任务
if [ "$OS" = "alpine" ]; then
    # 确保 Alpine 的 cron 目录存在
    mkdir -p /var/spool/cron/crontabs
    # 检查是否已经存在该任务,不存在则追加
    if ! crontab -l 2>/dev/null | grep -q "zram-optimize"; then
        (crontab -l 2>/dev/null; echo "0 3 * * * /usr/local/bin/zram-optimize.sh") | crontab -
    fi
    # 确保 cron 服务在 Alpine 中已启动
    rc-service crond start 2>/dev/null
    rc-update add crond default 2>/dev/null
else
    # Debian 逻辑保持不变
    (crontab -l 2>/dev/null | grep -v "zram-optimize"; echo "0 3 * * * /usr/local/bin/zram-optimize.sh") | crontab -
fi

echo "--- 4. 初始碎片整理 ---"
/usr/local/bin/zram-optimize.sh

echo "-------------------------------------------"
echo "✅ 所有配置已完成!"
echo "状态查看: zramctl"
echo "内核参数: swappiness=$(sysctl -n vm.swappiness), page-cluster=$(sysctl -n vm.page-cluster)"
echo "维护计划: 每天凌晨 3:00 自动整理碎片"
echo "-------------------------------------------"
zramctl

脚本新增细节说明:

  1. 初始整理:脚本在安装结束时会自动运行一次 /usr/local/bin/zram-optimize.sh。这样即使你是在一个已经运行了很久、内存很乱的系统上安装,也能立刻获得干净的压缩空间。
  2. 静默维护:通过 crontab 写入的任务会自动过滤重复项。如果你多次运行脚本,它不会产生一堆重复的定时任务。
  3. 碎片整理逻辑
  • 写入 /sys/block/zram0/compact 是目前 Linux 内核处理 zram 外部碎片最高效、最安全的方式。
  • 它不会导致系统卡顿,只是在后台重新排列压缩块。
  1. Alpine 兼容性补丁:在 Alpine 节点增加了 apk add bash。虽然 Alpine 默认是 sh,但为了 Crontab 和维护脚本的通用性,安装 bash 会更稳妥。

运行建议:

在 300MB 的小鸡上,这个脚本能帮你守住最后几 MB 的内存阵地;而在 2GB 的 VPS 上,配合 swappiness=100,它能让你的机器像拥有 4GB+ 内存一样流畅。

你可以把这个脚本存为 zram_pro.sh,以后每次开新机器,直接跑一下就搞定了!

这个版本已经深度考虑了优先级(Priority)以及与其他 Swap 设备共存的问题

在内存管理中,优先级是决定 zram 是否“有效”的关键。如果 zram 的优先级低于硬盘 Swap,系统会先去读写极慢的硬盘,zram 就成了摆设。

脚本中关于优先级的三个核心设计:

1. 强制高优先级 (-p 100)

在 Debian 的启动脚本逻辑中,我使用了:
swapon -p 100 /dev/zram0

  • 对比: 默认情况下,Linux 自动挂载的硬盘 Swap 优先级通常是 -2-1
  • 结果: 将 zram 设为 100,确保内核在需要交换内存时,100% 优先选择 zram。只有当 zram 被填满后,才会去碰慢速的硬盘 Swap。

2. 内核参数配合 (swappiness=100)

优先级决定了“往哪写”,而 swappiness 决定了“什么时候写”。

  • 通过设置 vm.swappiness=100,我们告诉内核:“别犹豫,只要有不常用的数据,立刻丢进高优先级的 zram 里。”
  • 这避免了系统在内存快憋死时才去急匆匆压缩,从而提高了整体响应速度。

3. 覆盖旧配置 (swapoffreset)

在 Debian 的启动脚本里,逻辑是先执行 swapoff

  • 这确保了如果系统之前已经有一个低优先级的 zram 节点,它会被彻底清理并按照我们设定的高优先级重新加载。

如何在运行后验证优先级?

运行脚本后,请执行以下命令:

swapon --show

你看到的输出应该类似这样:

NAME TYPE SIZE USED PRIO
/dev/zram0 partition 2G 100M 100
/swap.img file 2G 0B -2
  • 只要 zram0PRIO 数值比其他的 ,你的设置就是完美的。

补充一个极小概率的风险提示:

如果你同时运行了多个 zram 设备(比如 zram0, zram1),由于脚本只操作了 zram0,建议保持 num_devices=1。该脚本已经默认处理了这一点,确保所有压缩任务都集中在那个高优先级的 zram0 上。

配置好 zram 后,你的 VPS 性能会显著提升,但在日常运维中,还有几个**“深水区”**的问题需要你留意,以确保长期稳定:

1. 警惕“内存放大”后的假象

zram 让你拥有了“逻辑上”更大的内存,但物理内存(RAM)依然是有限的

  • 风险:如果你有 2G 内存,设置了 2G zram,逻辑上你有 4G 空间。但如果你的数据压缩率很低(例如运行已经加密或压缩过的视频流服务),zram 可能只能提供 1.2:1 的压缩比。
  • 后果:当物理内存被 zram 填满,而逻辑内存还没满时,系统会突然陷入极度卡顿或直接触发 OOM Killer
  • 对策:定期运行 zramctl 查看 COMPRDATA 的比例。如果比例长期低于 1.5:1,建议减小 zram 的设置。

2. CPU 是你的“新内存条”

zram 的读写本质上是 CPU 在拼命运行压缩/解压算法。

  • 注意:在 4C 2G 的机器上这通常不是问题,但在 单核小鸡 上,如果发生剧烈的内存交换,你会发现 CPU 占用率飙升
  • 现象:系统响应变慢(SSH 输入卡顿),但 top 显示内存还有剩余。
  • 对策:如果 CPU 压力太大,将算法从 zstd 改回 lz4lz4 压缩率稍低,但速度极快,对 CPU 负载极小。

3. 永远不要彻底关闭磁盘 Swap

虽然 zram 很快,但它不能完全替代硬盘 Swap。

  • 原因:当系统遇到极端极端压力时(物理内存和 zram 全满),如果没有硬盘 Swap 缓冲,系统会立即崩溃。
  • 对策:保持一个 512MB 或 1GB 的 /swapfile(优先级设低)。它就像是你汽车的安全气囊,平时不用,但关键时刻能救命。

4. 避免“双重压缩”

不要在 zram 上运行本身就有强力压缩机制的服务。

  • 典型案例:在 zram 开启的环境下,挂载一个加密的压缩卷(如加密的 Rclone 挂载)。
  • 后果:CPU 会浪费在两次无效压缩上,且压缩率几乎为 0(因为加密数据不可被二次压缩),这纯属浪费资源。

5. 编译大型软件时的坑

如果你在 2G 的 VPS 上尝试编译 nginxnodejs 等大型源码:

  • 风险:编译器(如 gcc)会消耗巨大的瞬时内存。如果这些数据还没来得及被内核判断为“不常用”并丢进 zram,物理内存就会瞬间爆表。
  • 对策:在编译前,手动运行一次 sync && echo 3 > /proc/sys/vm/drop_caches 释放缓存,给物理内存腾出呼吸空间。

总结检查清单:

  • [ ] swapon --show: 确保 zram 优先级最高。
  • [ ] zramctl: 观察压缩率(1.5:1 以上为优)。
  • [ ] CPU 负载: 观察大量写内存时 CPU 是否可以接受。
  • [ ] 持久化: 确保 /etc/sysctl.conf 里的 swappiness=100 重启后依然存在。

可以用 iostat 或特定工具观察这个虚拟设备的“读写速度”