zswap¶
概述¶
Zswap 是用于交换页面的轻量级压缩缓存。它获取正在被换出的页面,并尝试将它们压缩到动态分配的基于 RAM 的内存池中。 zswap 基本上是用 CPU 周期来换取可能减少的交换 I/O。如果从压缩缓存读取比从交换设备读取更快,那么这种权衡也会带来显著的性能提升。
一些潜在的好处
具有有限 RAM 容量的桌面/笔记本电脑用户可以减轻交换带来的性能影响。
过度分配的虚拟机可以共享一个通用的 I/O 资源,从而显著降低它们的交换 I/O 压力,避免虚拟机管理程序进行严厉的 I/O 节流。这使得更多的工作能够完成,同时对虚拟机工作负载和共享 I/O 子系统的虚拟机的影响更小。
使用 SSD 作为交换设备的用户可以通过大幅减少缩短寿命的写入来延长设备的使用寿命。
当压缩池达到其大小限制时,Zswap 会以 LRU 为基础从压缩缓存中逐出页面到后备交换设备。 此要求已在先前的社区讨论中确定。
Zswap 是否在启动时启用取决于是否启用了 CONFIG_ZSWAP_DEFAULT_ON
Kconfig 选项。 然后可以通过提供内核命令行 zswap.enabled=
选项来覆盖此设置,例如 zswap.enabled=0
。 也可以在运行时使用 sysfs 接口启用和禁用 Zswap。 在运行时启用 zswap 的示例命令,假设 sysfs 安装在 /sys
,是
echo 1 > /sys/module/zswap/parameters/enabled
在运行时禁用 zswap 时,它将停止存储正在被换出的页面。 但是,它_不会_立即写出或错误地将其中的页面恢复到内存中。 存储在 zswap 中的页面将保留在压缩池中,直到它们失效或错误地恢复到内存中。 为了强制所有页面退出压缩池,对交换设备执行 swapoff 将错误地将所有换出的页面(包括压缩池中的页面)恢复到内存中。
设计¶
Zswap 从交换子系统接收用于压缩的页面,并且能够以 LRU 为基础从其自身的压缩池中逐出页面,并在压缩池已满的情况下将它们写回到后备交换设备。
Zswap 使用 zpool 来管理压缩内存池。 zpool 中的每个分配都不能直接通过地址访问。 相反,分配例程返回一个句柄,并且必须先映射该句柄才能被访问。 压缩内存池按需增长,并随着压缩页面的释放而缩小。 该池不是预先分配的。 默认情况下,会创建在 CONFIG_ZSWAP_ZPOOL_DEFAULT
Kconfig 选项中选择类型的 zpool,但可以通过设置 zpool
属性在启动时覆盖它,例如 zswap.zpool=zsmalloc
。 也可以使用 sysfs zpool
属性在运行时更改它,例如
echo zsmalloc > /sys/module/zswap/parameters/zpool
zsmalloc 类型的 zpool 具有复杂的压缩页面存储方法,它可以实现很大的存储密度。
当交换页面从换出传递到 zswap 时,zswap 会维护交换条目的映射(交换类型和交换偏移量的组合)到引用该压缩交换页面的 zpool 句柄。 此映射是通过每个交换类型的红黑树实现的。 交换偏移量是树节点的搜索键。
在作为交换条目的 PTE 上的页面错误期间,交换代码调用 zswap 加载函数以将页面解压缩到页面错误处理程序分配的页面中。
一旦没有 PTE 引用存储在 zswap 中的交换页面(即,swap_map 中的计数变为 0),交换代码就会调用 zswap 失效函数来释放压缩条目。
Zswap 寻求在策略上保持简单。 Sysfs 属性允许一个用户控制的策略
max_pool_percent - 压缩池可以占用内存的最大百分比。
默认压缩器在 CONFIG_ZSWAP_COMPRESSOR_DEFAULT
Kconfig 选项中选择,但可以通过设置 compressor
属性在启动时覆盖它,例如 zswap.compressor=lzo
。 也可以使用 sysfs “compressor” 属性在运行时更改它,例如
echo lzo > /sys/module/zswap/parameters/compressor
当在运行时更改 zpool 和/或压缩器参数时,任何现有的压缩页面都不会被修改; 它们保留在它们自己的 zpool 中。 当请求旧 zpool 中的页面时,它会使用其原始压缩器进行解压缩。 一旦从旧 zpool 中删除了所有页面,zpool 及其压缩器就会被释放。
zswap 中的一些页面是相同值填充页面(即,页面的内容具有相同的值或重复的模式)。 这些页面包括零填充页面,它们的处理方式不同。 在存储操作期间,在压缩页面之前检查页面是否为相同值填充页面。 如果为真,则页面的压缩长度设置为零,并存储模式或相同填充值。
为了防止 zswap 在 zswap 已满并且交换压力很高时缩小池(这将导致页面在 zswap 池中进出翻转,没有任何实际好处,但会导致系统性能下降),引入了一个特殊参数来实现一种滞后效应,以拒绝将页面放入 zswap 池,直到它有足够的空间,如果已达到限制。 要设置 zswap 在已满后将再次开始接受页面的阈值,请使用 sysfs accept_threshold_percent
属性,例如
echo 80 > /sys/module/zswap/parameters/accept_threshold_percent
将此参数设置为 100 将禁用滞后效应。
一些用户无法容忍伴随 zswap 存储失败和 zswap 写回的交换。 可以按 cgroup 禁用交换(无需禁用 zswap 本身),如下所示
echo 0 > /sys/fs/cgroup/<cgroup-name>/memory.zswap.writeback
请注意,如果存储失败反复出现(例如,如果页面不可压缩),用户可能会在禁用写回后观察到回收效率低下(因为相同的页面可能会一次又一次地被拒绝)。
当 zswap 池中存在大量冷内存时,主动将这些冷页面写入交换空间并回收内存以供其他用例使用可能是有利的。 默认情况下,zswap 收缩器已禁用。 用户可以按如下方式启用它
echo Y > /sys/module/zswap/parameters/shrinker_enabled
如果选择了 CONFIG_ZSWAP_SHRINKER_DEFAULT_ON
,则可以在启动时启用此功能。
提供了一个 debugfs 接口,用于显示有关池大小、存储的页面数、相同值填充页面以及页面被拒绝的各种原因的各种统计信息。