zram

出自 ArchWiki

zram,以前称为 compcache,是一个 Linux 内核模块,用于在 RAM 中创建压缩块设备,即具有即时磁盘压缩的 RAM 磁盘。使用 zram 创建的块设备可以用于交换空间或作为通用 RAM 磁盘。zram 最常见的两个用途是存储临时文件 (/tmp) 和作为交换设备。最初,zram 只有后一种功能,因此原名“compcache”(“压缩缓存”)。

用作交换空间

最初,创建的 zram 块设备不保留或使用任何 RAM。只有当文件需要或想要被换出时,它们才会被压缩并移动到 zram 块设备中。然后,zram 块设备将根据需要动态增长或缩小。

即使假设 zstd 仅实现保守的 1:2 压缩比(实际数据表明常见的比例为 1:3),zram 也将提供比没有内存压缩的情况下能够在 RAM 中存储更多内容的优势。

注意
  • 配置 zram 时,zram 设备的大小控制它可以存储的最大未压缩数据量,而不是最大压缩大小。您可以将 zram 的大小配置为等于甚至大于系统的物理 RAM 容量,只要物理 RAM 上的压缩大小不超过系统的物理 RAM 容量即可。
  • 如果相关的 zswap 内核功能保持启用状态,它将阻止 zram 被有效使用。这是因为 zswap 充当 zram 前面的交换缓存,拦截并压缩被驱逐的内存页,然后它们才能到达 zram。尽管 zramctl(8) 的输出如此,但在这种情况下,zswap 的大部分是未使用的。因此,建议在启动前使用内核参数或 sysfs 设置永久禁用 zswap
  • 不支持休眠到 zram 上的交换空间,即使 zram 配置了永久存储上的后备设备。logind 将防止尝试休眠到 zram 上的交换空间。
提示: 您可以使用 mem_limit 参数指定 ZRAM 可以用来存储压缩数据的最大内存量。

一个简单的起始大小是系统总内存的一半。

手动

要设置一个使用 zstd 压缩算法的 zram 设备,其容量为系统内存的一半,并具有高于正常的优先级(仅适用于当前会话)

# modprobe zram
# zramctl /dev/zram0 --algorithm zstd --size "$(($(grep -Po 'MemTotal:\s*\K\d+' /proc/meminfo)/2))KiB"
# mkswap -U clear /dev/zram0
# swapon --discard --priority 100 /dev/zram0

要再次禁用它,可以重新启动或运行

# swapoff /dev/zram0
# modprobe -r zram

zram 模块的官方文档中提供了所有步骤、选项和潜在问题的详细说明。

对于永久解决方案,请使用以下部分之一的方法。

使用 udev 规则

下面的示例描述了如何在启动时使用单个 udev 规则自动设置 zram 上的交换空间。应该不需要额外的软件包即可使其工作。

显式在启动时加载模块

/etc/modules-load.d/zram.conf
zram

创建以下udev 规则,根据需要调整 disksize 属性

/etc/udev/rules.d/99-zram.rules
ACTION=="add", KERNEL=="zram0", ATTR{initstate}=="0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="4G", RUN="/usr/bin/mkswap -U clear %N", TAG+="systemd"

/dev/zram 添加到您的 fstab 中,并设置高于默认的优先级

/etc/fstab
/dev/zram0 none swap defaults,discard,pri=100 0 0

使用 zram-generator

zram-generator 提供 systemd-zram-setup@zramN.service 单元,以自动初始化 zram 设备,而无需用户 启用/启动 模板或其实例。请参阅 zram-generator(8)

要使用它,安装 zram-generator,并创建包含以下内容的 /etc/systemd/zram-generator.conf

/etc/systemd/zram-generator.conf
[zram0]
zram-size = min(ram / 2, 4096)
compression-algorithm = zstd

zram-size 是 zram 设备的大小(以 MiB 为单位),您可以使用 ram 来表示总内存。

compression-algorithm 指定用于在 zram 设备中压缩的算法。 cat /sys/block/zram0/comp_algorithm 给出了可用的压缩算法(以及括号中包含的当前算法)。请参阅 zram-generator.conf(5)

然后运行 daemon-reload启动 您配置的 systemd-zram-setup@zramN.service 实例(N 与数字实例 ID 匹配,在本例中为 systemd-zram-setup@zram0.service)。

您可以通过读取 systemd-zram-setup@zramN.service 实例的 单元状态,使用 zramctl(8) 或使用 swapon(8)检查您配置的 /dev/zramN 设备的交换状态

使用 zramswap

zramswapAUR 提供了一个自动化脚本,用于设置具有更高优先级的交换空间,默认大小为系统 RAM 大小的 20%。要在每次启动时自动执行此操作,启用 zramswap.service

技巧与窍门

检查 zram 统计信息

使用 zramctl(8)。示例

$ zramctl
NAME       ALGORITHM DISKSIZE  DATA  COMPR  TOTAL STREAMS MOUNTPOINT
/dev/zram0 zstd           32G  1.9G 318.6M 424.9M      16 [SWAP]
  • DISKSIZE = 32G:此 zram 设备将最多存储 32 GiB 的未压缩数据。
  • DATA = 1.9G:当前,此 zram 设备中存储了 1.9 GiB(未压缩)的数据
  • COMPR = 318.6M:1.9 GiB 未压缩数据被压缩为 318.6 MiB
  • TOTAL = 424.9M:包括元数据,1.9 GiB 的未压缩数据正在使用 424.9 MiB 的物理 RAM

多个 zram 设备

默认情况下,加载 zram 模块会创建一个 /dev/zram0 设备。

如果您需要多个 /dev/zram 设备,请使用 num_devices 内核模块参数 指定数量,或者根据需要稍后添加它们

优化 zram 上的交换空间

由于 zram 的行为与磁盘交换空间不同,我们可以配置系统的交换空间以充分利用 zram 的优势

/etc/sysctl.d/99-vm-zram-parameters.conf
vm.swappiness = 180
vm.watermark_boost_factor = 0
vm.watermark_scale_factor = 125
vm.page-cluster = 0

配置说明

这些值是 Pop!_OS 使用的值。Pop!_OS GitHub pull 请求也链接到 r/Fedora 用户进行的一些测试,该测试确定 vm.page-cluster = 0 是理想的。他们还发现较高的 swappiness 值是理想的,这与 内核文档 的建议相符

默认值为 60。
对于内存交换空间(如 zram 或 zswap)以及在比文件系统更快的设备上具有交换空间的混合设置,可以考虑超过 100 的值。例如,如果针对交换设备的随机 IO 平均比来自文件系统的 IO 快 2 倍,则 swappiness 应为 133(x + 2x = 200,2x = 133.33)。

在配备硬盘驱动器的系统上,针对 zswap 设备的随机 I/O 将比针对文件系统的 I/O 快几个数量级,因此 swappiness 应约为 200。即使在配备快速 SSD 的系统上,较高的 swappiness 值也可能是理想的。

为 zram 块启用后备设备

可以将 zram 配置为在内存压力下将不可压缩的页面推送到指定的块设备。

要手动添加后备设备

# echo /dev/sdX > /sys/block/zram0/backing_dev

要使用 zram-generator 为您的 zram 块设备添加后备设备,请在您要添加后备设备的 [zramX] 设备下更新 /etc/systemd/zram-generator.conf,内容如下

/etc/systemd/zram-generator.conf
writeback-device=/dev/disk/by-partuuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

将 zram 用于非交换目的

zram 也可以用作通用的 RAM 支持的块设备,例如,/dev/ram 物理内存使用量更少,但性能略低。但是,有一些注意事项

  • 没有分区表支持(不会自动创建 /dev/zramxpy)。
  • 块大小固定为 4 kiB。

解决此问题的显而易见的方法是在 zram 之上堆叠一个循环设备,使用 losetup,使用 -b 选项指定所需的块大小,并使用 -P 选项处理分区表并自动创建分区循环设备。

# zramctl -f -s NG
/dev/zramx

将磁盘映像复制到新的 /dev/zramx,然后创建循环设备。如果磁盘映像具有分区表,则循环设备的块大小必须与分区表使用的块大小匹配,通常为 512 或 4096 字节。

# losetup -f -b 512 -P /dev/zramx
# ls /dev/loop*
/dev/loop0 /dev/loop0p1 /dev/loop0p2
# mount /dev/loop0p1 /mnt/boot
# mount /dev/loop0p2 /mnt/root
注意
  • zram 设备编号取决于预先存在的 zram 设备,其大小应足以容纳磁盘映像。
  • ls /dev/loop* 的输出取决于磁盘映像的内容。

参见