注意:zswap和zram二者不可共存,使用zswap时一定要关闭zram
注意:该教程部分需要进行重启,请确认服务器是否存在业务
ZRAM
ZRAM使用:
- ZRAM 在内存中创建块设备
- 当数据写入ZRAM数据块块时候,数据压缩
- 当ZRAM作为交换设备时,ZRAM比其他交换设备优先级更高: 被换出的页面优先发送到ZRAM设备(你可以理解为内存到内存),直到ZRAM满了以后才会使用其他任何交换设备
ZRAM优点:
- 独立于其他(物理)交换设备
- 当没有交换分区时候可以使用ZRAM来扩展可用内存: 你可以理解为ZRAM是内存中的一个天然压缩分区,所有进入这个内存区域的数据都会得到压缩,所以相对于普通内存区域可以存储更多内存数据
ZRAM缺点:
- 会影响其他交换设备(HDD/SSD)使用: ZRAM是一个独立的交换设备,一旦满了以后,任何需要换出的新页面都会直接发送到下一个交换设备,这就导致:
- 存在LRU(最近最少使用)反转的可能性: 最近交换的数据将进入慢速磁盘,而很久以前交换出的非活动页面将保留在快速ZRAM中(也就是因为ZRAM存满了以后,内存交换数据就会直接存到磁盘交换文件中,而不是将ZRAM中冷数据换到磁盘,热数据放到ZRAM)
- 由于发送到磁盘交换的数据没有压缩,会导致从磁盘来回的数据消耗大量带宽
ZRAM状态:
- ZRAM已经合并到内核主线3.14
- 一旦在系统中启用ZRAM,就需要一些用户空间配置来设置交换设备并使用它们
ZSWAP
ZSWAP使用:
frontswap
系统hooks尝试换出页面,并使用zswap作为HDD/SSD交换设备的回写缓存(你可以理解为物理磁盘配置了一个巨大的缓存,所有写磁盘会经过这个缓存)
- zswap会尝试压缩页面,但如果是可压缩性较差的数据,则直接写入磁盘;如果数据被压缩,则存储在zswap的内存池中
- 当RAM中压缩页面总数超过一定大小时将页面换出内存,则最近最少使用(LRU)压缩页面将被写入磁盘(因为不太可能很快用到)
ZSWAP优点:
- 非常高效地使用RAM和基于磁盘的交换: 通过减少所需的写入和读取次数(数据被压缩并保存在RAM中)以及由于数据处于压缩形式而减少这些I/O操作的带宽,最大限度地减少磁盘I/O
ZSWAP缺点:
- zswap是基于磁盘的交换系统的增强,所以它依赖硬盘上的交换分区(实际上就是磁盘交换分区的缓存,类似于以前硬件RAID卡上的缓存)
ZSWAP状态:
1:在运行时启用 Zswap
1. 首先,运行命令检查当前 zswap 模块参数:
systool -v -m zswap
如果未找到命令,请运行sudo apt-get install sysfsutils
。在终端输出中,它应该打印包含“enabled =“N””的项目,表示该功能未启用。
前置条件
安装 zstd and Z3fold
sudo apt-get install checkinstall build-essential
sudo apt-get install zstd
编辑模块
sudo nano /etc/initramfs-tools/modules
在文件末尾添加
zstd
zstd_compress
z3fold
更新内存文件系统
sudo update-initramfs -u -k all
**2.写入 zswap
配置文件:
echo 1 | sudo tee /sys/module/zswap/parameters/enabled
echo zstd | sudo tee /sys/module/zswap/parameters/compressor
echo z3fold | sudo tee /sys/module/zswap/parameters/zpool
您也可以运行上面类似的命令来配置更多 zswap 参数。要进行验证,只需再次运行 systool -v -m zswap
命令即可
2:启动时启用 zswap
注:如果Grub 的配置文件不存在可直接重启检查配置是否为预期配置
前面的命令在运行时启用 zswap,但在系统重新启动后它不会持续。
为了使其持久化,您可以配置 Grub 引导加载程序以在启动时加载内核参数。
1. 首先,运行命令来编辑 Grub 的配置文件:
sudo nano /etc/default/grub
这里我使用适用于大多数桌面环境的 nano
命令行文本编辑器。对于 24.04,您可以将其替换为默认 GNOME 的 gnome-text-editor
;对于 22.04 及更早版本,您可以将其替换为 gedit
,或者根据您的桌面使用其他编辑器。
2. 当文件打开时,添加以下内核参数作为“GRUB_CMDLINE_LINUX_DEFAULT”的值:
zswap.enabled=1 zswap.compressor=zstd zswap.zpool=z3fold
您可以根据需要添加/删除更多 zswap 参数,并用空格分隔它们。最后,按 Ctrl+S 保存,按 Ctrl+X 退出 Nano 文本编辑器。
3.保存更改后,运行以下命令重新生成 Grub 启动菜单项
sudo update-grub
最终步骤
完成上述步骤后重启系统
验证 ZSWAP 配置是否符合预期
systool -v -m zswap
验证 ZSWAP 是否使用了 zstd and z3fold
sudo dmesg | grep -i zswap
输出
zswap: loaded using pool zstd/z3fold
下面是z3fold和zsmalloc的区别,我使用的是z3fold
z3fold
z3fold is a special purpose allocator for storing compressed pages. It is designed to store up to three compressed pages per physical page. It is a zbud derivative which allows for higher compression ratio keeping the simplicity and determinism of its predecessor.
Z3Fold是用于存储压缩页面的特殊目的分配器。它旨在每个物理页面最多存储三个压缩页面。它是Zbud衍生物,允许更高的压缩比保持其前身的简单性和决定性。
The main differences between z3fold and zbud are:
Z3Fold和Zbud之间的主要区别是:
unlike zbud, z3fold allows for up to PAGE_SIZE allocations
与Zbud不同,Z3Fold允许最多page_size分配
z3fold can hold up to 3 compressed pages in its page
Z3fold在其页面中最多可以保留3个压缩页面
z3fold doesn’t export any API itself and is thus intended to be used via the zpool API.
Z3Fold不会导出任何API本身,因此旨在通过ZPOOL API使用。
To keep the determinism and simplicity, z3fold, just like zbud, always stores an integral number of compressed pages per page, but it can store up to 3 pages unlike zbud which can store at most 2. Therefore the compression ratio goes to around 2.7x while zbud’s one is around 1.7x.
为了保持确定性和简单性,Z3Fold就像Zbud一样,总是存储每页不可或缺的压缩页面,但是与最多可以存储2个Zbud不同,它最多可以存储3页。因此,压缩比约为2.7倍。而Zbud的一个约为1.7倍。
Unlike zbud (but like zsmalloc for that matter) z3fold_alloc() does not return a dereferenceable pointer. Instead, it returns an unsigned long handle which encodes actual location of the allocated object.
与Zbud不同(但与Zsmalloc一样)z3fold_alloc()不会返回可解释指针。取而代之的是,它返回一个无符号的长把手,该长柄编码分配的对象的实际位置。
Keeping effective compression ratio close to zsmalloc’s, z3fold doesn’t depend on MMU enabled and provides more predictable reclaim behavior which makes it a better fit for small and response-critical systems.
保持有效的压缩率接近ZSMALLOC的压缩率,Z3Fold不取决于启用MMU,并提供了更可预测的回收行为,这使其更适合小型和响应响应的系统。
zsmalloc
This allocator is designed for use with zram. Thus, the allocator is supposed to work well under low memory conditions. In particular, it never attempts higher order page allocation which is very likely to fail under memory pressure. On the other hand, if we just use single (0-order) pages, it would suffer from very high fragmentation – any object of size PAGE_SIZE/2 or larger would occupy an entire page. This was one of the major issues with its predecessor (xvmalloc).
该分配器设计用于ZRAM。因此,分配器应该在低记忆条件下效果很好。特别是,它从未尝试过在内存压力下很可能失败的高阶页面分配。另一方面,如果我们只使用单个(0阶)页面,它将遭受非常高的碎片的影响 - 任何大小page_size/2或更大的对象都会占据整个页面。这是其前任(XVMalloc)的主要问题之一。
To overcome these issues, zsmalloc allocates a bunch of 0-order pages and links them together using various ‘struct page’ fields. These linked pages act as a single higher-order page i.e. an object can span 0-order page boundaries. The code refers to these linked pages as a single entity called zspage.
为了克服这些问题,Zsmalloc分配了一堆0阶页面,并使用各种“结构页”字段将它们链接在一起。这些链接的页面充当单个高阶页面,即对象可以跨越0阶页边界。代码将这些链接的页面称为一个称为zspage的单个实体。
For simplicity, zsmalloc can only allocate objects of size up to PAGE_SIZE since this satisfies the requirements of all its current users (in the worst case, page is incompressible and is thus stored “as-is” i.e. in uncompressed form). For allocation requests larger than this size, failure is returned (see zs_malloc).
为简单起见,Zsmalloc只能将大小的对象分配到Page_size,因为这满足了所有当前用户的要求(在最坏的情况下,Page是不可压缩的,因此以未压缩的形式存储了“ AS-IS” IE)。对于大于此尺寸的分配请求,返回故障(请参阅ZS_MALLOC)。
Additionally, zs_malloc() does not return a dereferenceable pointer. Instead, it returns an opaque handle (unsigned long) which encodes actual location of the allocated object. The reason for this indirection is that zsmalloc does not keep zspages permanently mapped since that would cause issues on 32-bit systems where the VA region for kernel space mappings is very small. So, before using the allocating memory, the object has to be mapped using zs_map_object() to get a usable pointer and subsequently unmapped using zs_unmap_object().
此外,ZS_MALLOC()不会返回可取代指针。相反,它返回不透明的手柄(未签名长),该手柄编码分配的对象的实际位置。这种间接的原因是Zsmalloc不会永久映射Zspages,因为这将在32位系统上引起问题,在32位系统上,VA区域的内核空间映射非常小。因此,在使用分配内存之前,必须使用zs_map_object()映射对象,以获取可用的指针,然后使用zs_unmap_object()将其取下。