Btrfs文件系统

简单的介绍一下

btrfs,全称为b-tree,江湖上也有人管他叫butter FS或Better FS,遵循GPL协定,由oracle公司从2007年左右开始研发。

核心特性

  1. Cow:写时复制,可将预修改的文件复制一份,接着在副本上完成修改,而后把文件指针指向副本文件,一旦改错了还可以随时回退。
  2. 校验码机制:支持数据及元数据校验码机制,方便快速检测文件是否受损,可自动尝试修复,极大了保障了数据可靠性。
  3. 快照:支持快照,类似lvm的快照,不过它还支持快照的快照和对单个文件做快照。
  4. RAID:支持RAID。
  5. 多物理卷支持:btrfs文件系统可由多个底层的物理卷组成,类似逻辑卷中的vg。
  6. 子卷:可在一个文件系统中创建多个子卷,接着将每个子卷单独使用或挂载。
  7. 动态伸缩:支持联机实现物理卷的添加、移除、修改操作。
  8. 透明压缩:通过消耗CPU的时钟周期来完成数据压缩存放,并且在用户读取时自动解压缩,整个过程用户是无感的,不过压缩与解压就会消耗CPU的时钟周期。

命令

创建并挂载brtfs文件系统

mkfs.btrfs [option] DEV:创建btrfs
option:
-L:指定卷标。
-m:指定元数据如何存放,支持raid0|1|5|6|10、single、dup,确保底层设备够用。
-d:指定数据如何存放,支持raid0|1|5|6|10、single。
-O:指定启用的特性,需在格式化时使用,但是一些老内核可能不支持全部特性,可使用mkfd.brtfs -O list-all查看支持的特性。

挂载btrfs和挂载普通文件系统无异。

mount -t brtfs DEV MOUNT_POINT:-t也可以缺省。
启用透明压缩机制:mount -o comperess={lzo|zlib} DEVICE MOUNT_POINT

管理brtfs命令

命令格式:btrfs <subcommand> [option]

1. brtfs filesystem [option]:管理btrfs系统的命令。
option:
(1) show|[--mounted|--all-devices|<path>|<uudi>|device|<label>]:显示brtfs文件系统,支持多种指定方式。
(2) sync <path>:强制将指定设备存储在内存上的数据同步到磁盘上。
(3) df <path>:查看指定已挂载设备的空间使用率情况。
(4) defragmeng [option] <file> | <dir>:做磁盘碎片整理。
(5) resize [+|-]#[gkm] <path> | max <path>:改变文件系统大小。
(6) label [<dev>|<mountpoint>] [<newlabel>] :显示卷标。

2. btrfs device [option]:管理硬件设备的命令。
option:
(1) add DEV path:新增设备。
(2) deleta DEV path:移除一个设备,btrfs可以智能将预拆除设备上的数据移除,并且文件系统逻辑边界与物理边界自动调整,\\
但是在拆除前,一定确保拆除后的磁盘大小能够承载现有数据。
(3) scan:扫描设备。
(4) ready:将指定设备转为备用状态。
(5) state:显示I\O统计数据。

3. btrfs balance [option] path:实现数据均衡。
option:
(1) status <path>:查看文件系统均衡进度。
(2) start [[-m|-d]convert] <path>:启动均衡,可以修改数据及元数据的组织机制,或仅均衡数据。
(3) stop <path>:终止均衡。
(4) pause <path>:暂停均衡。
(5) resume <path>:继续均衡。

4. btrfs subvolume [option] path:子卷管理命令。
option:
(1) list path:列出子卷。
(2) create /path/sub_path:创建子卷,直接在父卷下使用类似创建目录的形式创建子卷。
(3) delete /path:删除子卷
(4) show path:显示子卷的详细信息。
(5) snapshot VOL VOL_SNAP:创建快照卷。
(6) get default:查看默认卷。
(7) set default:设置默认卷。
可以单独挂载子卷,使用mount -o subvol=SUB_NAME DEV /path,也可以使用卷ID实现挂载。

5. btrfs-convert [option] DEV
option:
(1) -r:回滚文件系统。

一次完整的操作过程

  1. 使用3个卷创建1个btrfs文件系统。
  2. 调整brtfs的空间大小,查看前后空间对比。增删底层设备,查看空间变化及底层物理卷信息。
  3. 新增1个设备,完成数据的balance。
  4. 不挂载父卷的情况下挂载子卷,查看文件信息。
  5. 对某个物理卷创建快照,验证效果。对brtfs底层卷数量进行增删,查看空间变化情况,查看底层物理卷信息。
  6. 选个分区,先格式化成ext4文件系统,在转换成btrfs,在转换成ext4。

分步开始:

  • 使用3个卷创建1个btrfs文件系统。

首先在虚拟机中加入4块硬盘或4个分区,格式化其中3个创建成btrfs。

[root@node1 ~]# mkfs.btrfs -L mydata /dev/sdb1 /dev/sdb2 /dev/sdb3
btrfs-progs v4.9.1
See http://btrfs.wiki.kernel.org for more information.

Label: mydata
UUID: 43f82814-243e-4154-b3f5-be980e5b3cb0
Node size: 16384
Sector size: 4096
Filesystem size: 65.00GiB
Block group profiles:
Data: RAID0 3.00GiB
Metadata: RAID1 1.00GiB
System: RAID1 8.00MiB
SSD detected: no
Incompat features: extref, skinny-metadata
Number of devices: 3
Devices:
ID SIZE PATH
1 20.00GiB /dev/sdb1
2 30.00GiB /dev/sdb2
3 15.00GiB /dev/sdb3
[root@node1 ~]# blkid /dev/sdb1
/dev/sdb1: LABEL="mydata" UUID="43f82814-243e-4154-b3f5-be980e5b3cb0" UUID_SUB="611caec5-f15a-4e4a-b734-2564a7e6151c" TYPE="btrfs"
[root@node1 ~]# blkid /dev/sdb2
/dev/sdb2: LABEL="mydata" UUID="43f82814-243e-4154-b3f5-be980e5b3cb0" UUID_SUB="0b963519-fe9d-4107-a283-d34057e07be7" TYPE="btrfs"
[root@node1 ~]# blkid /dev/sdb3
/dev/sdb3: LABEL="mydata" UUID="43f82814-243e-4154-b3f5-be980e5b3cb0" UUID_SUB="fb035730-f919-486b-9ce3-a60fdae3621b" TYPE="btrfs"

这里可以看到,3个分区共同组成了1个btrfs,并且每个分区使用不同的UUID_SUB来区分。

  • 调整brtfs的空间大小,查看前后空间对比。增删底层设备,查看空间变化及底层物理卷信息。
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb1 65G 18M 52G 1% /mydata

分区大小分别为 20G、30G、15G共同组成 65G 大小的Btrfs。
[root@node1 ~]# btrfs filesystem resize -20G /mydata
Resize '/mydata' of '-20G'
ERROR: unable to resize '/mydata': Invalid argument <------这里-20G报错了,提示参数错误。

[root@node1 ~]# btrfs filesystem resize -19G /mydata
Resize '/mydata' of '-19G'
ERROR: unable to resize '/mydata': No space left on device <---------这里-19G报错了,提示磁盘空间不足。

[root@node1 ~]# btrfs filesystem resize -18G /mydata
Resize '/mydata' of '-18G'
执行成功后,我又将空间调整为max。
[root@node1 ~]# btrfs filesystem resize -15G /mydata
Resize '/mydata' of '-15G'
执行成功后,我又将空间调整为max。
[root@node1 ~]# btrfs filesystem resize max /mydata
Resize '/mydata' of 'max'
[root@node1 ~]# btrfs filesystem resize -10G /mydata
Resize '/mydata' of '-10G'

这里遇到个小问题,空间减少20G与空间减少19G都报错了,但是报错信息不同,自我推测原因为Btrfs存储元数据及数据会默认启用RAID机制,应该是-20G或19G就会破坏现在的RAID级别,所以它拒绝修改,于是我尝试着将调整btrfs的数据组织机制,尝试过raid0、raid1、raid5、single的不同组合(single暂未设置成功),有趣的是,调整数据组织机制后,执行缩减空间大小命令时,报错区间也变化了。目前还没摸清具体的缩减取值区间及规律,不过我笃定数据组织机制就是限制空间缩减的元凶。

  • 新增1个设备,完成数据的balance。
    首先查看下现在的底层设备信息。
[root@node1 ~]# btrfs filesystem show
Label: 'mydata' uuid: 43f82814-243e-4154-b3f5-be980e5b3cb0
Total devices 3 FS bytes used 704.00KiB
devid 1 size 2.00GiB used 1.16GiB path /dev/sdb1
devid 2 size 30.00GiB used 1.16GiB path /dev/sdb2
devid 3 size 15.00GiB used 1.16GiB path /dev/sdb3
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb1 47G 17M 46G 1% /mydata

可以看到,现在这个brtfs共有3个分区,并且空间共47G。现在我使用dd命令,向btrfs中填充一些数据。

[root@node1 ~]# dd if=/dev/zero of=/mydata/data.dd bs=1G count=10
10+0 records in
10+0 records out
10737418240 bytes (11 GB) copied, 38.9366 s, 276 MB/s

[root@node1 mydata]# ll -h
total 10G
-rw-r--r--. 1 root root 10G May 12 21:19 data.dd

执行命令将新的分区加入这个btrfs。

[root@node1 mydata]# btrfs device add /dev/sdb5 /mydata
[root@node1 mydata]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb1 82G 11G 63G 14% /mydata
[root@node1 mydata]# btrfs filesystem show /mydata
Label: 'mydata' uuid: 43f82814-243e-4154-b3f5-be980e5b3cb0
Total devices 4 FS bytes used 10.01GiB
devid 1 size 2.00GiB used 2.00GiB path /dev/sdb1
devid 2 size 30.00GiB used 9.00GiB path /dev/sdb2
devid 3 size 15.00GiB used 9.00GiB path /dev/sdb3
devid 4 size 35.00GiB used 0.00B path /dev/sdb5

现在已经完成了新分区加入,接着对数据进行balance。

[root@node1 mydata]# btrfs balance start /mydata
WARNING:

Full balance without filters requested. This operation is very
intense and takes potentially very long. It is recommended to
use the balance filters to narrow down the balanced data.
Use 'btrfs balance start --full-balance' option to skip this
warning. The operation will start in 10 seconds.
Use Ctrl-C to stop it.
10 9 8 7 6 5 4 3 2 1
Starting balance without any filters.
Done, had to relocate 11 out of 11 chunks
有道机翻:完全平衡,没有过滤器要求。这次行动非常紧张,可能需要很长时间。
建议使用均衡过滤器来缩小被均衡的数据范围。使用'btrfs balance start——full-balance'选项跳过此警告。
过程中查看balance状态:
[root@node1 ~]# btrfs balance status /mydata
Balance on '/mydata' is running
2 out of about 11 chunks balanced (3 considered), 82% left

不管如何,最后它提示了Done。那就暂且算验证成功了吧。😄

  • 不挂载父卷的情况下挂载子卷,查看文件信息。

ok,首先看看btrfs上的子卷信息。

[root@node1 ~]# btrfs subvolume show /mydata
/mydata
Name: <FS_TREE>
UUID: -
Parent UUID: -
Received UUID: -
Creation time: -
Subvolume ID: 5
Generation: 193
Gen at creation: 0
Parent ID: 0
Top level ID: 0
Flags: -
Snapshot(s):

输出的信息可以看到,现在就一个卷。
那我们来创建一个:

[root@node1 ~]# btrfs subvolume create /mydata/test_sub
Create subvolume '/mydata/test_sub'
[root@node1 ~]# btrfs subvolume create /mydata/test_sub2
Create subvolume '/mydata/test_sub2'
[root@node1 ~]# btrfs subvolume show /mydata
/mydata
Name: <FS_TREE>
UUID: -
Parent UUID: -
Received UUID: -
Creation time: -
Subvolume ID: 5
Generation: 200
Gen at creation: 0
Parent ID: 0
Top level ID: 0
Flags: -
Snapshot(s):
test_sub
test_sub2

注意看输出信息的最后一行,Snapshot(s)下已经显示了两个子卷。
挂载两个子卷

[root@node1 ~]# mount -o subvol=/test_sub /dev/sdb1 /sub1
[root@node1 ~]# mount -o subvol=/test_sub2 /dev/sdb1 /sub2
[root@node1 ~]# ll /sub1 /sub2
/sub1:
total 0

/sub2:
total 0
[root@node1 ~]# mount
/dev/sdb1 on /sub1 type btrfs (rw,relatime,seclabel,space_cache,subvolid=283,subvol=/test_sub)
/dev/sdb1 on /sub2 type btrfs (rw,relatime,seclabel,space_cache,subvolid=284,subvol=/test_sub2)
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb1 82G 11G 66G 14% /sub1
/dev/sdb1 82G 11G 66G 14% /sub2

子卷中并没有看到刚刚dd命令填充的数据,且可用空间信息的是相同的。
向子卷中加入数据点数据,卸载子卷,挂载父卷,查看数据。

[root@node1 ~]# ls /mydata/test_sub{,2}
/mydata/test_sub:
test.snap

/mydata/test_sub2:

验证完毕

  • 对某个物理卷创建快照,验证效果。对brtfs底层卷数量进行增删,查看空间变化情况,查看底层物理卷信息
    我就以子卷test_sub为例,先touch一个文件,接着对它创建快照卷。
btrfs subvolume snapshot /mydata/test_sub /mydata/sub1-snap
Create a snapshot of '/mydata/test_sub' in '/mydata/sub1-snap'
[root@node1 ~]# echo 'busyops@outlook.com' >> /mydata/test_sub/test.snap
[root@node1 ~]# cat /mydata/sub1-snap/test.snap
this is first line.
ni hao ni hao.
busyops@outlook.com
yi jian san lian.
tou bi,dian zan, shoucang.
SSSSSSSSSSSSSSSSSSSSSSSSSSS
DDDDDDDDDDDDDDDDDDDDDDDDDDD
[root@node1 ~]# cat /mydata/test_sub/test.snap
this is first line.
ni hao ni hao.
busyops@outlook.com
yi jian san lian.
tou bi,dian zan, shoucang.
SSSSSSSSSSSSSSSSSSSSSSSSSSS
DDDDDDDDDDDDDDDDDDDDDDDDDDD
busyops@outlook.com

快照卷验证完毕,下面在btrfs系统中移除设备。首先查看文件系统信息:

[root@node1 ~]# btrfs filesystem show /mydata
Label: 'mydata' uuid: 43f82814-243e-4154-b3f5-be980e5b3cb0
Total devices 4 FS bytes used 10.01GiB
devid 1 size 2.00GiB used 1023.00MiB path /dev/sdb1
devid 2 size 30.00GiB used 5.53GiB path /dev/sdb2
devid 3 size 15.00GiB used 5.53GiB path /dev/sdb3
devid 4 size 35.00GiB used 5.53GiB path /dev/sdb5
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb1 82G 11G 66G 14% /mydata

现在btrfs中共有4个分区,尝试移除设备。

[root@node1 ~]# btrfs device remove /dev/sdb1 /mydata
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb2 80G 11G 63G 14% /mydata
[root@node1 ~]# btrfs device remove /dev/sdb2 /mydata
[root@node1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
devtmpfs 1.4G 0 1.4G 0% /dev
tmpfs 1.4G 0 1.4G 0% /dev/shm
tmpfs 1.4G 9.5M 1.4G 1% /run
tmpfs 1.4G 0 1.4G 0% /sys/fs/cgroup
/dev/mapper/centos-root 50G 1.4G 49G 3% /
/dev/mapper/centos-home 46G 33M 46G 1% /home
/dev/sda1 1014M 150M 865M 15% /boot
tmpfs 283M 0 283M 0% /run/user/0
/dev/sdb3 50G 11G 29G 27% /mydata
[root@node1 ~]# btrfs device remove /dev/sdb3 /mydata
ERROR: error removing device '/dev/sdb3': unable to go below two \\
devices on raid5

当我想仅留一块硬盘时,又报错了。提示2个设备不能跑raid5,于是我又看是尝试各种数据组织记得的组合。但最终也未能将设备减少到仅剩1个。
在移除设备时,命令执行会卡一下,我想正是卡的时候,btrfs正将预移除设备上的数据移至其他分区,缩减及扩展逻辑、物理边界。正是这种机制,降低了人为操作失误的风险。

  • 选个分区,先格式化成ext4文件系统,在转换成btrfs,在转换成ext4。
    就拿/dev/sdb1来做测试吧。
[root@node1 ~]# mkfs.ext4 -L test /dev/sdb1
mke2fs 1.42.9 (28-Dec-2013)
Filesystem label=test
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
1310720 inodes, 5242880 blocks
262144 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2153775104
160 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
4096000

Allocating group tables: done
Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done
[root@node1 ~]# mount /dev/sdb1 /sub1
[root@node1 ~]# ls /sub1
lost+found
[root@node1 ~]# cp /etc/fstab /sub1
[root@node1 ~]# ls /sub1
fstab lost+found
[root@node1 ~]# umount /sub1
[root@node1 ~]# fsck /dev/sdb1
fsck from util-linux 2.23.2
e2fsck 1.42.9 (28-Dec-2013)
test: clean, 12/1310720 files, 126323/5242880 blocks
[root@node1 ~]# btrfs-convert /dev/sdb1
create btrfs filesystem:
blocksize: 4096
nodesize: 16384
features: extref, skinny-metadata (default)
creating ext2 image file
creating btrfs metadatacopy inodes [o] [ 0/ 12]
conversion complete[root@node1 ~]# mount /dev/sdb1 /sub1
[root@node1 ~]# cat /sub1/fstab

#
# /etc/fstab
# Created by anaconda on Sun Feb 16 09:28:27 2020
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=7b9dd426-d07f-49cb-b500-5f04fa478bb2 /boot xfs defaults 0 0
/dev/mapper/centos-home /home xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
[root@node1 ~]# blkid /dev/sdb1
/dev/sdb1: LABEL="test" UUID="6e04f353-ff27-4ed0-8481-40415bc532d0" UUID_SUB="032eee39-e664-416a-9d3e-267ba48bfbff" TYPE="btrfs"

现在已将/dev/sdb1转换为了btrfs。在回退回去,同理步骤为卸载--> 检测--> 回退

[root@node1 mydata]# umount /dev/sdb1
[root@node1 mydata]# btrfsck /dev/sdb1
Checking filesystem on /dev/sdb1
UUID: 6e04f353-ff27-4ed0-8481-40415bc532d0
checking extents
checking free space cache
checking fs roots
checking csums
checking root refs
found 518221824 bytes used err is 0
total csum bytes: 505292
total tree bytes: 802816
total fs tree bytes: 49152
total extent tree bytes: 16384
btree space waste bytes: 259806
file data blocks allocated: 517419008
referenced 517419008
[root@node1 ~]# btrfs-convert -r /dev/sdb1
rollback complete

btrfs检测需要使用btrfsck命令,完毕。


总结

通过学习btrfs及课后实验的过程中,总结如下:

  1. 需掌握btrfs的重要特性如动态伸缩、写时复制、数据校验码、数据组织机制。
  2. 难点在于摸清数据组织机制的规律。如何才能最大化的利用好磁盘空间是考验对btrfs的理解难处。在第一遍做实验时,我用的3块不同空间大小的磁盘完成的,缩减磁盘空间报错后,也认为磁盘空间不一致不利于我寻求数据组织机制规律,毕竟不管哪种raid阵列磁盘空间都取得是最小值,但我认为btrfs应对这种情况有优化。不过我还是使用了3个20G的分区重新尝试了,能力有限,未能摸清规律。此问题留存了。
  3. 命令使用时,需注意有些地方引用btrfs的方式类似于目录一样,不可给设备名称。
  4. 做实验时发现虚拟机给的100G硬盘,到centos 7 系统中显示为107G。
  5. 创建快照卷时,需要先将父卷挂载。

留存问题:

  • 数据组织机制到底规律是啥。😯

作者:busyops
邮箱:busyops@outlook.com
本文仅是我的一些简单理解,欢迎随时探讨
最后更新时间为:2021-05-12 23:21:19