在Linux云服务器上开启zSwap
什么是 zSwap
zSwap
是 Linux 内核的一个功能,它为交换页提供了一个压缩的回写缓存,作为一种虚拟内存压缩形式。当内存页要被换出时,zSwap
不会把它们移到交换设备上,而是对它们进行压缩,然后把它们存储到系统 RAM 中动态分配的内存池中。后来,向实际的交换设备的回写被推迟了,甚至完全避免了,从而大大减少了需要交换的 Linux 系统的 I/O,其代价是需要额外的 CPU 周期来执行压缩。
zSwap
允许 Linux 更有效地利用 RAM,因为它实际上增加了内存容量,而不是在压缩/解压缩交换页时稍微增加 CPU 的使用。与 zram
相比的区别在于,zswap
与 swap
设备协同工作,而 zram
是内存中的交换设备,不需要后备交换设备。zSwap
存在于内核中,但默认并没有开启,要使用它必须通过修改配置文件开启。
主流内存压缩技术
zSwap
zSwap
是在 memory 与 flash 之间的一层缓存,当内存需要 swap
出去磁盘的时候,先通过压缩放到 zSwap
中去,zSwap
空间按需增长。达到一定程度后则会按照 LRU
的顺序(前提是使用的内存分配方法需要支持 LRU
)将就最旧的 page 解压写入磁盘 swap device,之后将当前的 page 压缩写入 zSwap
。
zSwap
本身存在一些缺陷或问题:如果开启当 zSwap
满交换出 backing store 的功能, 由于需要将 zSwap
里的内存按 LRU 顺序解压再 swap out,这就要求内存分配器支持 LRU
功能;如果不开启当 zSwap
满交换出 backing store 的功能, 和 zRam
是类似的。
zRAM
zRram
即压缩的内存,使用内存模拟 block device 的做法。实际不会写到块设备中去,只会压缩后写到模拟的块设备中,其实也就是还是在 RAM 中,只是通过压缩了。由于压缩和解压缩的速度远比读写 I/O 好,因此在移动终端设备广泛被应用。
zRram
本身存在一些缺陷或问题:zRam
大小是可灵活配置的,配置多少成为了一个问题;使用 zRam
可能会在低内存场景由于频繁的内存压缩导致 kswapd 进程占 CPU 高;增大了 zRam
配置,对系统内存碎片是否有影响
zCache
zCache
是 oracle 提出的一种实现文件页压缩技术,也是 memory 与 block dev 之间的一层存储,与 zSwap
比较接近,但 zCache
目前压缩的是文件页,而 zSwap
和 zRAM
压缩是匿名页。
开启 zSwap
使用内核参数开启
以 root
身份编辑 grub
配置文件
1 | sudo vim /etc/default/grub |
在 GRUB_CMDLINE_LINUX_DEFAULT
行加入 zswap.enabled=1 zswap.compressor=zstd zswap.zpool=z3fold
,完成后如下
1 | GRUB_CMDLINE_LINUX_DEFAULT="quiet splash zswap.enabled=1 zswap.compressor=zstd zswap.zpool=z3fold" |
更新 grub
配置
1 | sudo update-grub |
重启即可
通过 sysfs
接口进行更改
由于 zSwap 配置可以在运行时通过 sysfs 接口进行更改,在上述方法无效时,可以通过 service 的方式在开机时自动启动 zSwap
创建 /etc/systemd/system/zswap.service
1 | [Unit] |
创建 /usr/bin/init-zswap
1 | touch /usr/bin/init-zswap |
编辑 /usr/bin/init-zswap
1 |
|
完成后 sudo systemctl enable zswap
,重启即可
配置 zSwap 参数
这部分内容来自 zswap - Arch Linux中文维基
当前参数
zswap 有几个可自定义的参数。可以使用以下方式显示实时设置:
1 | $ grep -R . /sys/module/zswap/parameters |
1 | /sys/module/zswap/parameters/same_filled_pages_enabled:Y |
见 zswap 文档 获取不同参数的描述。
显示初始配置的引导时加载消息可以通过以下方式检索:
1 | dmesg | grep zswap: |
1 | [ 0.317569] zswap: loaded using pool lz4/z3fold |
设定参数
使用 sysfs
每个设置都可以在运行时通过 sysfs 接口进行更改。作为示例,要更改 compressor 参数:
1 | echo lz4 > /sys/module/zswap/parameters/compressor |
使用内核引导参数
要持久化参数更改,必须在内核引导参数中添加相应的选项,例如 zswap.compressor=lz4。因此,要永久设定上述所有设置,必须添加以下内核参数:
1 | zswap.enabled=1 zswap.compressor=lz4 zswap.max_pool_percent=20 zswap.zpool=z3fold |
当通过引导参数更改压缩算法时,需要确保在引导期间尽早加载相应的压缩模块(参考 #压缩算法)。
最大池大小
存储池不是预先分配的,它可以增长到可用内存总量的一定百分比,默认情况下最多占内存总量的20%。一旦达到此阈值,就会将页从池中逐出到交换设备中。压缩池的最大大小由参数 max_pool_percent
控制。
压缩存储池分配器
zpool
参数控制压缩存储池的管理。
使用 zbud
数据分配器,2个压缩对象被存储到1个页中,这将压缩比限制为2或更小。
更好的 z3fold 分配器允许每页最多3个压缩对象。z3fold
的压缩比通常为2.7,而 zbud
的压缩比通常为1.7。
默认情况下,会创建 z3fold
类型的 zpool
。使用内核参数 zswap.zpool
在启动时选择另一种方法。数据分配器也可以在稍后阶段通过 sysfs
接口进行更改。
压缩算法
对于页的压缩,zswap 使用内核加密 API 提供的压缩器模块。默认情况下会使用 lz4
压缩算法,但也可以在启动时使用 zswap.compressor
更改压缩算法。其他选项包括 deflate
, lz4hc
, lzo
, lzo-rle
, 842
和 zstd
。
使用 sysfs
在运行时更改压缩不会有问题,但在本例中,zswap 从 lz4
开始,并在稍后阶段切换到定义的算法。要立即使用另一种算法启动 zswap,必须通过内核引导参数进行设定,并且内核必须尽早加载相应的模块。这可以通过以下步骤来实现:
- 将与所选压缩器相关的模块添加到 mkinitcpio#模块(MODULES) 数组中。
- 修改 mkinitcpio 配置后重新生成 ramdisk 环境:见 mkinitcpio#创建和启用镜像。
- 在内核参数中将
zswap.compressor
设定为你选择的算法。
在下次启动时,见 #当前参数来检查 zswap 现在是否使用了请求的压缩器。