系统盘不足-ZFS上创建swap的⚠️事项-最好转移重建新分区

,

root@ultra4:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda 253:0 0 10G 0 disk
├─vda1 253:1 0 1M 0 part
├─vda2 253:2 0 191M 0 part /boot/efi
├─vda3 253:3 0 763M 0 part /boot
└─vda4 253:4 0 9.1G 0 part
└─vda4_crypt 252:0 0 9G 0 crypt
└─vg-gen 252:1 0 9G 0 lvm /
vdb 253:16 0 200G 0 disk
└─vdb1 253:17 0 200G 0 part
我的vbd1现在是zfs数据集,可以把swap放在sdb1? 有什么建议

你提到的 sdb1 应该是指 lsblk 输出里的 vdb1(虚拟化环境下的第二块盘)。

要把 Swap 放到已经作为 ZFS 的 vdb1 上,技术上完全可行,但有一点非常重要的架构风险需要你知晓。


:stop_sign: 核心核心核心警告:内存死锁风险 (Memory Deadlock)

Linux 官方和 ZFS 社区不极其推荐将 Swap 放在 ZFS 之上。

为什么?
当系统内存耗尽(OOM)时,操作系统会尝试把内存数据写入 Swap。但 ZFS 是一个非常复杂的底层文件系统,它在写入数据时(计算校验和、管理 ARC 缓存、压缩等)自身也需要申请系统内存
这就可能陷入一个死锁套娃:系统内存不足 → 触发 Swap → ZFS 写入 Swap 却需要申请内存 → 系统无内存可给 → 整个系统瞬间卡死挂起。


如果你评估了风险,或者系统本身内存很充裕(只是想挂个 Swap 兜底),请务必使用 Zvol(ZFS 卷) 来做 Swap,而绝对不要在 ZFS 数据集里直接建一个 swapfile

以下是具体的实施步骤和优化建议:

方案一:在 ZFS 中创建 Zvol 作 Swap(不破坏现有 ZFS)

如果你的 vdb1 已经存了数据,无法重新分区,可以用这个方法。我们需要通过一系列严格的参数来压榨 ZFS 的内存开销,以降低死锁概率。

1. 获取你的 ZFS 存储池(Pool)名称

zpool list

假设你的 Pool 名字叫 mypool

2. 创建一个精心优化过的 Zvol

运行以下命令(这里以创建 16GB 的 Swap 为例):

sudo zfs create -V 16G \
  -b $(getconf PAGESIZE) \
  -o compression=off \
  -o logbias=throughput \
  -o sync=always \
  -o primarycache=metadata \
  -o secondarycache=none \
  -o com.sun:auto-snapshot=false \
  mypool/swap

:light_bulb: 参数为什么这么配?

  • -b $(getconf PAGESIZE):强制块大小与系统内存页(通常是 4K)对齐。
  • compression=off:关闭压缩,避免写 Swap 时消耗额外的 CPU 和内存。
  • sync=always:强迫数据立即落盘,不留在内存缓存里。
  • primarycache=metadata最关键! 绝不让 ZFS 把 Swap 数据又缓存到自己的 ARC 内存里(那成了内存左手倒右手,毫无意义)。

3. 格式化为 Swap 分区

Zvol 创建后,会在 /dev/zvol/ 下生成一个块设备:

sudo mkswap -f /dev/zvol/mypool/swap

4. 写入 /etc/fstab 实现开机自启

打开 /etc/fstab

sudo nano /etc/fstab

添加或修改为以下这行:

/dev/zvol/mypool/swap swap swap defaults 0 0

5. 启用并验证

sudo swapon /dev/zvol/mypool/swap
swapon --show


方案二:最完美的终极建议(重新分区)

如果你的 vdb1 目前是空的,或者里面的数据可以先备份出来,强烈建议把 vdb 彻底重新分区

  1. 划分一个 16G - 32G 的裸分区(比如 vdb1),直接格式化为标准的 Linux Swap(不经过 ZFS)。
  2. 剩下的 180G 左右空间划分成另一个分区(比如 vdb2),用来给 ZFS 做存储池。

这样做的优势:Swap 读写直接走块设备驱动,绕过了 ZFS 复杂的内存管理,100% 免疫内存死锁风险,性能也是最高的。

修改swapfile位置的步骤:

修改 Linux 中的 Swap 文件路径并扩大容量,核心流程是先关闭旧 Swap → 创建并配置新 Swap → 修改 fstab 配置 → 开启新 Swap → 删除旧文件

以下是详细的操作步骤(假设你要将新 Swap 文件存放在 /mnt/new_swapfile,且容量扩大到 8GB):

1. 关闭当前的 Swap 空间

首先,需要安全地关闭系统目前正在使用的旧 Swap 文件:

sudo swapoff /swapfile

2. 创建新的大容量 Swap 文件

使用 fallocatedd 命令在目标路径创建新文件。这里以创建 8GB 容量为例:

  • 推荐方法(速度极快):
sudo fallocate -l 8G /mnt/new_swapfile

  • 备用方法(如果你的文件系统是 XFS 等不支持 fallocate 的老版本,可以使用 dd):
    sudo dd if=/dev/zero of=/mnt/new_swapfile bs=1M count=8192
    ```

### 3. 设置正确的安全权限
Swap 文件必须严格限制权限,只允许 root 用户读写,否则系统会报错且存在安全隐患:
```bash
sudo chmod 600 /mnt/new_swapfile

4. 将文件格式化为 Swap 格式

把刚刚创建的大文件初始化为 Swap 分区格式:

sudo mkswap /mnt/new_swapfile

输出中会显示类似 Setting up swapspace version 1, size = 8 GiB... 的提示。

5. 修改 /etc/fstab 配置文件

编辑备份好后的 /etc/fstab 文件,让系统在开机时自动挂载新的 Swap 文件。

使用你习惯的文本编辑器打开它:

sudo nano /etc/fstab

找到原本的那一行:

/swapfile swap swap defaults 0 0

将其修改为新的路径(注意:只需改路径,后面的参数保持不变):

/mnt/new_swapfile swap swap defaults 0 0

保存并退出编辑器。

6. 启用新的 Swap 文件

sudo swapon /mnt/new_swapfile

7. 验证是否修改并扩大成功

运行以下命令检查当前的 Swap 状态和容量:

swapon --show

或者查看内存使用情况:

free -h

你应该能看到路径已经变成了 /mnt/new_swapfile,且总容量变成了 8GB 左右。

8. 清理旧的 Swap 文件

确认新 Swap 正常工作后,就可以把原本根目录下的旧文件删掉以释放硬盘空间了:

sudo rm /swapfile


:warning: 避坑小提示:如果你的新路径存放在 Btrfs 文件系统上,直接创建 Swap 文件会复杂一些(需要创建独立子卷并禁用写时复制 chattr +C)。如果是常见的 Ext4XFS 文件系统,直接按照上述步骤操作即可。


真的不能直接修改/缩减这个sdb1分区。 这属于 Linux 存储管理中一个非常经典的“雷区”。

如果这是普通的 Ext4、XFS 或 Btrfs 文件系统,你确实可以通过工具在线或离线裁剪分区。但对于 ZFS 来说,这是绝对的禁区


为什么不能直接动 vdb1

ZFS 本身不仅是个文件系统,它还兼职做了逻辑卷管理器(Volume Manager)。它的核心设计逻辑是“只能扩容,不能缩容”。

如果你用 fdiskpartedGParted 强行把 vdb1 从 200G 砍到 180G:

  1. ZFS 毫不知情:ZFS 的元数据里依然记录着自己拥有 200G 的空间。
  2. 毁灭性灾难:当 ZFS 往它认为存在的最后 20G 空间写入数据时,底层的物理扇区其实已经被你划走或删除了。这会导致 ZFS 的树状哈希结构彻底损坏,整个存储池会瞬间崩溃(Faulted),里面的数据将面临毁灭性丢失且几乎无法恢复

如果你一定要做“真正的”裸分区 Swap,怎么做?

如果你不想用上一条回答里的 Zvol(折中方案),而是坚持想要一个不经过 ZFS 的、独立干净的 Swap 裸分区,你必须走“备份 → 销毁 → 重新分区 → 恢复”的流程:

  1. 备份数据:把当前 vdb1 里的所有重要数据拷贝或使用 zfs send 备份到其他安全的地方。
  2. 销毁存储池
sudo zpool destroy <你的存储池名字>

  1. 重新划分 vdb 磁盘:使用 fdisk /dev/vdb,删掉原来的 vdb1,重新规划两个分区:
  • vdb1:大小 16G,专门用来做标准 Swap。
  • vdb2:剩下的 184G,用来重新创建 ZFS 存储池。
  1. 配置新 Swap 和 ZFS
  • vdb1 格式化并启用为 Swap (mkswap /dev/vdb1 → 写入 fstab)。
  • vdb2 重新建立你的 ZFS 存储池,并把备份的数据导回来。

:light_bulb: 总结建议

之所以在上一次回复中推荐你使用 Zvol(方案一),就是为了保全你当前的分区和数据,在不重新格式化、不折腾整个硬盘的前提下,直接在 ZFS 内部“挖”出一块空间当 Swap 顶替使用。

  • 如果 vdb1 里面已经有大量重要数据:请老老实实采用上一条回复的 方案一(创建 Zvol),这是唯一不需要动分区的在线改法。
  • 如果 vdb1 目前是空的,或者数据微不足道:强烈建议直接彻底干掉它,按照上面的步骤重新分区,划分出一个独立的 /dev/vdb1 作为 Swap,这样性能最好,也最安全。