我的NAS 一直是禁用掉了 SWAP,因为关闭 SWAP 可以有效降低群晖 NAS 硬盘炒豆子的声音,群晖的这个 SWAP 机制简直是绝了,比如你的 4 个盘位都插上了硬盘,那它会在这 4 个块硬盘上都创建 SWAP 文件,并且启用 RAID1,也就是说要响,所有硬盘全响。。。
因为我的 NAS 是 16GB 内存,所以我对 SWAP 基本没有需求,但是不少同学的 NAS 可能也就 4GB,或者 8GB 内存,如果启用了虚拟机或者 docker 容器比较多,就会造成内存紧张,禁用 SWAP 可能会导致 OOM,所以我的建议是开启 ZRAM,并设置高优先级,这样内存不足时就会优先使用 ZRAM 了。
ZRAM 介绍
zram,旧称为 compcache,是一个用于在内存中创建压缩的块设备的 Linux 内核模块,即带实时磁盘压缩的内存盘。通过 zram 创建的块设备可以用作 swap 或是内存盘。zram 有两个常见的应用场景,一个是储存临时文件(
引用自 archlinuxcn.org,本文主要是将 zram 用作 swap。/tmp
),另一个是用作 swap。早期 zram 只有前一个功能,也是它原名 “compcache” (compressed cache) 的由来。
)
一键脚本
我编写了一个群晖 DSM 一键启用 ZRAM 的脚本,默认为百分之 50 RAM,压缩算法 LZO(我的 DS918+实测,群晖zram 默认只支持这一种算法,不支持 zstd 算法,比较无语。)
复制这段代码,创建名为manage_zram.sh
的脚本。
使用方法,终端或群晖计划任务中运行该脚本sudo ./manage_zram.sh
#!/bin/bash
# 脚本名称: manage_zram.sh # 描述: 这个脚本用于在群晖NAS上管理zram设备,包括创建、配置和停用zram。 # 使用方法: sudo ./manage_zram.sh [-p <百分比>] [-d] [-m <最大压缩流>] # 选项: # -p, --percent: 设置zram大小占总内存的百分比(默认50%) # -d, --disable: 停用zram设备 # -m, --max-streams: 设置最大压缩流数量(默认为CPU核心数)
set -e # 遇到错误立即退出 set -u # 使用未定义的变量时报错
# 默认值 RAM_PERCENT=50 DISABLE_ZRAM=false MAX_COMP_STREAMS=$(nproc)
# 错误处理函数 error_exit() { echo "错误: $1" >&2 exit 1 }
# 日志函数 log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" }
# 解析命令行参数 while [[ $# -gt 0 ]]; do case $1 in -p|--percent) RAM_PERCENT="$2" if ! [[ $RAM_PERCENT =~ ^[0-9]+$ ]] || [ $RAM_PERCENT -lt 1 ] || [ $RAM_PERCENT -gt 100 ]; then error_exit "RAM百分比必须是1到100之间的整数。" fi shift 2 ;; -d|--disable) DISABLE_ZRAM=true shift ;; -m|--max-streams) MAX_COMP_STREAMS="$2" if ! [[ $MAX_COMP_STREAMS =~ ^[0-9]+$ ]] || [ $MAX_COMP_STREAMS -lt 1 ]; then error_exit "最大压缩流数量必须是正整数。" fi shift 2 ;; *) error_exit "未知选项: $1\n使用方法: $0 [-p <百分比>] [-d] [-m <最大压缩流>]" ;; esac done
# 检查root权限 [[ $EUID -ne 0 ]] && error_exit "此脚本必须以root权限运行。"
# 检查是否为DSM系统 [[ ! -f "/etc.defaults/VERSION" ]] && error_exit "无法检测到DSM系统,脚本可能无法正常工作。"
# 检查zram模块是否可用 check_zram_available() { if ! modprobe -n zram &>/dev/null; then error_exit "zram模块不可用。请确保您的系统支持zram。" fi }
# 停用zram函数 disable_zram() { local zram_devs=$(ls /dev/zram* 2>/dev/null) if [[ -n "$zram_devs" ]]; then for dev in $zram_devs; do swapoff $dev 2>/dev/null || log "无法停用 $dev" echo 1 > /sys/block/$(basename $dev)/reset 2>/dev/null || log "无法重置 $dev" done rmmod zram 2>/dev/null || log "无法卸载zram模块" log "zram已停用并移除。" else log "未检测到活动的zram设备。" fi }
# 配置和启用zram configure_zram() { # 加载zram模块 modprobe zram num_devices=1 || error_exit "无法加载zram模块。"
# 设置最大压缩流 echo $MAX_COMP_STREAMS > /sys/block/zram0/max_comp_streams || log "无法设置最大压缩流,使用默认值。"
# 计算zram大小 local TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}') local ZRAM_SIZE=$((TOTAL_MEM * 1024 * RAM_PERCENT / 100))
# 设置zram大小 echo $ZRAM_SIZE > /sys/block/zram0/disksize || error_exit "无法设置zram大小。"
# 创建swap并启用 mkswap /dev/zram0 || error_exit "无法创建swap分区。" swapon -p 100 /dev/zram0 || error_exit "无法启用zram swap。"
log "zram已成功配置并启用为swap" log "压缩算法: lzo (群晖NAS默认)" log "最大压缩流: $(cat /sys/block/zram0/max_comp_streams)" log "RAM使用百分比: $RAM_PERCENT%" log "zram大小: $((ZRAM_SIZE / 1024 / 1024)) MB" }
# 主逻辑 check_zram_available
if [[ $DISABLE_ZRAM = true ]]; then disable_zram else disable_zram # 先停用现有的zram设备 configure_zram fi
效果&性能测试(跑分)
性能测试:sudo fio -filename=/dev/block/zram0 -thread -rw=write -bs=32468k -size=500M -group_reporting -numjobs=1 -name=mytest
DS918+ 跑分数据(Intel J4125)
mytest: (g=0): rw=write, bs=(R) 31.7MiB-31.7MiB, (W) 31.7MiB-31.7MiB, (T) 31.7MiB-31.7MiB, ioengine=psync, iodepth=1 fio-3.33 Starting 1 thread mytest: Laying out IO file (1 file / 500MiB)
mytest: (groupid=0, jobs=1): err= 0: pid=6383: Thu Aug 15 16:00:40 2024 write: IOPS=36, BW=1149MiB/s (1205MB/s)(476MiB/414msec); 0 zone resets clat (usec): min=15108, max=15638, avg=15387.76, stdev=150.99 lat (usec): min=22538, max=23426, avg=23098.89, stdev=228.51 clat percentiles (usec): | 1.00th=[15139], 5.00th=[15139], 10.00th=[15139], 20.00th=[15270], | 30.00th=[15270], 40.00th=[15270], 50.00th=[15401], 60.00th=[15401], | 70.00th=[15533], 80.00th=[15533], 90.00th=[15533], 95.00th=[15664], | 99.00th=[15664], 99.50th=[15664], 99.90th=[15664], 99.95th=[15664], | 99.99th=[15664] lat (msec) : 20=100.00% cpu : usr=27.60%, sys=72.40%, ctx=11, majf=0, minf=0 IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0% submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0% issued rwts: total=0,15,0,0 short=0,0,0,0 dropped=0,0,0,0 latency : target=0, window=0, percentile=100.00%, depth=1
Run status group 0 (all jobs): WRITE: bw=1149MiB/s (1205MB/s), 1149MiB/s-1149MiB/s (1205MB/s-1205MB/s), io=476MiB (499MB), run=414-414msec