FreeBSD ZFS
ZFS是最好的文件系统
什么是 ZFS
zroot 数据存储
FreeBSD安装过程支持直接构建ZFS作为操作系统root存储,默认命名为 zroot zpool。我由于设备PCIe插槽有限(用于GPU)并且资金捉襟见肘,所以最终只在 一块NVMe 上使用默认的 zroot 存储池构建和使用ZFS。
FreeBSD installer过程中如果选择自动ZFS,会将整个磁盘数据抹掉然后分配3个分区:
- 分区1是
efi分区(FAT32) - 分区2是
freebsd-swap分区 - 分区3是
freebsd-zfs分区,也就是除了上述2个分区外,所有剩余磁盘空间都分配给zrootzpool
由于我计划构建一个FreeBSD和Linux(LFS)并存的系统,所以我在安装过程中采用了手工划分ZFS步骤
在FreeBSD安装过程中手工配置ZFS,以便限制默认 zroot zpool 使用 256G 空间,剩余磁盘空间后续用于Linux以及数据存储 zdata zpool:
-
当FreeBSD Installer安装过程到了
Partition分区步骤时,不能选择Auto ZFS,而是要选择shell选项,此时进入控制台 -
检查系统中有哪些磁盘
camcontrol devlist
可以看到第二行显示是 铠侠KIOXIA EXCERIA G2 NVMe SSD存储 ,识别为 nda0 , 将在 nda0 上安装FreeBSD:
<AHCI SGPIO Enclosure 2.00 0001> at scbus8 target 0 lun 0 (ses0,pass0)
<KIOXIA-EXCERIA G2 SSD ECFA17.1> at scbus9 target 0 lun 1 (pass1,nda0)
<SanDisk' Cruzer Fit 1.00> at scbus10 target 0 lun 0 (da0,pass3)
- 创建一个全新的分区表( 警告,会摧毁磁盘上所有数据 ):
# 如果这里出现报错提示nda0 busy,则可能是磁盘中原本有数据,需要使用 -F 参数
gpart destroy nda0
# 创建gpt分区表
gpart create -s gpt nda0
- 创建包含启动代码的分区(bootcade partition) 我的实践是创建UEFI Boot
gpart add -a 4k -s 260M -t efi nda0
# Create a FAT32 partition
newfs_msdos -F 32 -c 1 /dev/nda0p1
mount -t msdosfs -o longnames /dev/nda0p1 /mnt
mkdir -p /mnt/EFI/BOOT
cp /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
umount /mnt
-
创建分区:
-a <number>控制对齐-s <size>设置分区大小,如果没有指定分区大小,就会将磁盘剩余空间全部用掉(我设置指定256GB)
gpart add -a 1m -s 2G -t freebsd-swap -l swap0 nda0
gpart add -a 1m -s 256G -t freebsd-zfs -l disk0 nda0
- 创建ZFS Pool:
gpart show -p nda0
# 挂载tmpfs
mount -t tmpfs tmpfs /mnt
# 创建ZFS存储池
zpool create -o altroot=/mnt zroot nda0p3
- 现在需要依次创建完整的ZFS文件系统,以便安装程序能够正确分布目录:
# 设置默认的lz4压缩,默认配置通常适合
zfs set compress=on zroot
# 创建Boot环境的层次结构
zfs create -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=none zroot/ROOT/default
mount -t zfs zroot/ROOT/default /mnt
# 创建剩余文件系统
zfs create -o mountpoint=/tmp -o exec=on -o setuid=off zroot/tmp
zfs create -o canmount=off -o mountpoint=/usr zroot/usr
zfs create zroot/usr/home
zfs create -o exec=off -o setuid=off zroot/usr/src
zfs create zroot/usr/obj
zfs create -o mountpoint=/usr/ports -o setuid=off zroot/usr/ports
zfs create -o exec=off -o setuid=off zroot/usr/ports/distfiles
zfs create -o exec=off -o setuid=off zroot/usr/ports/packages
zfs create -o canmount=off -o mountpoint=/var zroot/var
zfs create -o exec=off -o setuid=off zroot/var/audit
zfs create -o exec=off -o setuid=off zroot/var/crash
zfs create -o exec=off -o setuid=off zroot/var/log
zfs create -o atime=on -o exec=off -o setuid=off zroot/var/mail
zfs create -o exec=on -o setuid=off zroot/var/tmp
# 链接和权限设置
ln -s /usr/home /mnt/home
chmod 1777 /mnt/var/tmp
chmod 1777 /mnt/tmp
- 配置启动环境
zpool set bootfs=zroot/ROOT/default zroot
- 创建
/tmp/bsdinstall_etc/fstab:
cat << EOF > /tmp/bsdinstall_etc/fstab
# Device Mountpoint FStype Options Dump Pass#
/dev/gpt/swap0 none swap sw 0 0
EOF
-
现在退出Shell,此时
bsdinstall就会继续完成安装(如果上述ZFS分区没有错误的话) -
在最后安装步骤,当安装程序提示时候要补充命令,一定要回答
yes,并完成以下命令(也就是设置系统默认启动时加载ZFS):
sysrc zfs_enable="YES"
echo 'zfs_load="YES"' >> /boot/loader.conf
compression=lz4 启用轻量级lz4压缩能够提升存储利用率,同时因为压缩数据也提高了存储IO性能(但消耗CPU计算资源)
zdata 数据存储
由于我的 组装服务器 只有一个PCIe插槽,通过拆分能够安装3个PCIe设备,我需要将宝贵的PCIe接口用于机器学习的GPU设备,所以最终我取消了 zdata 的多NVMe存储,而改为仅使用一块NVMe的 zroot 数据存储。
当生产环境中使用ZFS,建议构建 RAIDZ 确保数据安全
- 使用
geom检查磁盘列表
geom disk list
可以看到主机安装了1块NVMe磁盘,设备名是 ndaX :
Geom name: nda0
Providers:
1. Name: nda0
Mediasize: 2000398934016 (1.8T)
Sectorsize: 512
Mode: r2w2e4
descr: KIOXIA-EXCERIA G2 SSD
lunid: 00000000000000008ce38e030091c40e
ident: Y39B70RTK7AS
rotationrate: 0
fwsectors: 0
fwheads: 0
gpart 划分分区
- 如上文所述,我在安装过程中手工配置ZFS
zrootzpool,所以当前为操作系统分配的zroot存储池只占用部分存储空间,使用 gpart 检查磁盘分区:
gpart show nda0
当前有3个分区:
=> 40 3907029088 nda0 GPT (1.8T)
40 532480 1 efi (260M)
532520 2008 - free - (1.0M)
534528 4194304 2 freebsd-swap (2.0G)
4728832 536870912 3 freebsd-zfs (256G)
541599744 3365429384 - free - (1.6T)
- 在上述3个分区之后,再创建一个(分区4)分区(
-t linux-data表示是Linux分区),分配 256G (-s)并设置以 1M 大小进行对齐(-a 1M)
gpart add -t linux-data -a 1M -s 256G nda0
- 剩余磁盘空间再创建一个分区
gpart add -t freebsd-zfs -a 1M nda0
- 最终
gpart show nda0显示如下(添加了2个分区)
=> 40 3907029088 nda0 GPT (1.8T)
40 532480 1 efi (260M)
532520 2008 - free - (1.0M)
534528 4194304 2 freebsd-swap (2.0G)
4728832 536870912 3 freebsd-zfs (256G)
541599744 536870912 4 linux-data (256G)
1078470656 2828558336 5 freebsd-zfs (1.3T)
3907028992 136 - free - (68K)
创建 stripe 模式 ZFS pool zdata
- 构建的是
stripe模式,是为了追求实验环境容量最大化, 生产环境不可使用!!! - 生产环境请使用
RAIDZ-5
- 使用上述
gpart划分好的分区2(操作系统所在盘是分区4)来构建一个容量最大化的stripeZFS 存储池:
zpool create -f -o ashift=12 zdata /dev/nda0p5
# 启用压缩
zfs set compression=lz4 zdata
-o ashift=12的ashift属性设置为12,以对应 4KiB (4096字节)块大小。通常对于HDD和SSD,能够获得较好的性能和兼容性。底层是 512字节 一个扇区,所以2^12= 4096 就能够对齐和整块读写磁盘。如果没有指定这个 ashift 参数,ZFS会自动检测 ashift ,如果检测失败就会默认使用ashift=9,这会导致性能损失。这个 ashift 参数一旦设置,不能修改- 这里使用了
diskid来标记磁盘,以避免搞错磁盘
- 创建zfs卷集
# 存储文档的卷集,其他卷集主要在Jails中使用
zfs create zdata/docs
为后续 vm-bhyve运行虚拟化 准备,构建独立的dataset:
zfs create zdata/vms
# 为 vm-bhyve 提供独立的dataset
zfs create zdata/vms/.config
zfs create zdata/vms/.img
zfs create zdata/vms/.iso
zfs create zdata/vms/.templates
进一步阅读
- 使用GPT分区在ZFS上构建FreeBSD Root(安装)
- gpart实践(linux分区及zfs分区)
- ZFS Stripe条带化 (FreeBSD环境实践) 我最初构建
zdatazpool 使用了4块NVMe实现容量最大化,后改为单块磁盘