群晖 DSM 开启 ZRAM 内存压缩-增加可用内存

admin


本文最后更新于 2024年08月19日

我的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 有两个常见的应用场景,一个是储存临时文件(/tmp),另一个是用作 swap。早期 zram 只有前一个功能,也是它原名 “compcache” (compressed cache) 的由来。

引用自 archlinuxcn.org,本文主要是将 zram 用作 swap。

一键脚本

我编写了一个群晖 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


相关文章

群晖性能优化-降低swap使用率




1.360905s