您尚未登录。

#1 2012-05-18 13:50:10

sgsdxzy
Light
注册时间: 2012-05-17
帖子: 31

AcrhLinux实战btrfs

btrfs是linux下一代文件系统,由oracle、radhat、intel、suse等多个公司和社区研发,采用GPL协议发布(Linux Only),目前正逐步稳定下来。Arch的内核很新,也对btrfs提供了较好的支持,我尝试了一次全新的整个系统基于btrfs的安装,和大家分享一下心得。
    首先,为什么我们要用btrfs?btrfs有很多吸引人的特性,比如:
1、类似lvm的多设备文件系统,目前支持raid0、raid1、raid10,预计在3.5内核中加入raid5/6的支持。
2、类似于ZFS的pool概念:一个分卷(volume)可以横跨多个物理分区,分卷内有subvolume共享volume的空间。比如为了重装能保留/home,你的/分了20G,/home分了60G,某天/不够用了,怎么办?btrfs可以把/和/home作为subvolume,共享剩余空间,同时在/遇到不可逆损坏时保持/home的完整性。不过有一个限制:btrfs上不能放置swap文件,会损坏文件系统。请使用独立的swap分区。
3、快照。btrfs能对任何subvolume进行快照,同时其copy-on-write的特性可以让多个快照引用同一个文件,当文件在一个快照中被修改时再复制一份储存在这个快照中,所以说,一个快照初始时几乎不占硬盘空间,随着系统使用快照和当前系统的差异越来越大,快照才占用越来越多的空间。
4、透明压缩。支持文件系统级的压缩,目前支持zlib和lzo两种算法,后续会加入snappy和lz4等。现在系统往往硬盘读取速度是瓶颈,牺牲一些CPU时间压缩数据而减少硬盘读写往往能提高整体效率。 测评:http://www.phoronix.com/scan.php?page=a … 2638&num=1
5、设计时就考虑到了SSD的优化
    我觉得以上是比较吸引桌面用户的地方,还有很多别的特性可见:https://btrfs.wiki.kernel.org/index.php/Main_Page 可以说,目前来看,除了ZFS的deduplication功能,btrfs是一个能和ZFS正面抗衡的linux文件系统。
    为了尝试btrfs,我在我的15G小硬盘上重装了系统。系统安装和别的大致无异,但要注意一下几个方面:1、选择软件包时,选上btrfs-progs 2、我要讲讲subvolume的意义:btrfs,顾名思义,Btree(二叉树)是文件系统组织方式。subvolume就是森林的根,标识一个subvolume有两个数据:名称和ID。建立文件系统后,会自动生成总树根,没有名称,ID为0。之后你可以在下面建立文件、文件夹和子树,文件夹和子树中又能包含别的文件、文件夹和子树。子树和文件夹的区别在于,子树能够用mount命令直挂载在到目录根部,也可以对其快照而文件夹不行。为了更好的扩展性与快照回滚能力,建议把/安装在一个新的subvolume而不是总树根上。很不幸,arch默认的安装脚本不能满足我们的要求,我们来手动安装arch。下面演示创建一个/、一个/home和一个pkg子树,并为了稳妥将/boot分在另一个独立的ext4分区上。为什么建这个pkg子树呢?因为可以对subvolume指定不同的挂载选项,像pkg里面全是压缩包,自然就不用透明压缩,所以不需要compress(很可惜,到3.3内核还没有支持不同subvolume使用不同的压缩选项,以后会改进,见:https://btrfs.wiki.kernel.org/index.php … options.3F)。
    具体步骤可见:https://wiki.archlinux.org/index.php/In … Btrfs_root,我想有意愿折腾btrfs的不会被手动安装arch难到。用mkfs.btrfs创建一个类型为btrfs的分区,挂载到/mnt。cd到/mnt,执行以下命令:

btrfs subvolume create rootfs
btrfs subvolume create homefs
btrfs subvolume create pkg

之后用命令

btrfs subvolume list /mnt

可以看到这样的结果:

ID 256 top level 5 path rootfs
ID 260 top level 5 path homefs
ID 262 top level 5 path pkg

(我们的ID可能会不一样,以自己的为准)

    三个subvolume建立完成!但是这样还不够,我们要按照结构挂载。btrfs的挂载选项也很有讲究,具体见:https://btrfs.wiki.kernel.org/index.php/Mount_options
执行:

mount  -o remount,compress=lzo,space_cache,autodefrag /dev/sdaX /mnt
mkdir -p /mnt/rootfs/home /mnt/rootfs/var/cache/pacman/pkg /mnt/rootfs/dev /mnt/rootfs/proc /mnt/rootfs/sys
mkdir -p /mnt/rootfs/var/cache/pacman/pkg
mount  -o subvol=homefs,compress=lzo,space_cache,autodefrag /dev/sdaX /mnt/rootfs/home
mount  -o subvol=pkg,compress=lzo,space_cache,autodefrag /dev/sdaX /mnt/rootfs/var/cache/pacman/pkg
mount /dev/sdaY(ext4的boot分区) /mnt/rootfs/boot

subvol=<name>是指定挂载的subvol名称,也可以使用subvolid=ID。compress=lzo是在安装时就进行透明压缩,减小体积,提高性能。space_cache,autodefrag都是提高性能的选项。如果是ssd,可以加上ssd和discard。
    然后到/mnt/rootfs/中,执行

mount -o bind /dev dev/
mount -t proc /proc proc/
mount -t sysfs /sys sys/

    最后来一步pacman -r . -Sy base grub2-bios --ignore grub 安装系统。我试过,grub1不能从subvolume中启动,syslinux我不熟,听说也有问题,所以推荐grub2。安装grub2不多说了,https://wiki.archlinux.org/index.php/GRUB2#Installation
    之后就是/etc 中的设置了,按个人喜好,注意几个地方:
1、mkinitcpio的hook里加上btrfs,然后mkinitcpio -p linux重新生成镜像,不然多设备btrfs可能无法启动。会提示fsck.btrfs找不到,不用管,这个目前还没实现。
2、fstab要写好,我的是这样的:

……
/dev/sda10 / btrfs subvolid=256,defaults,compress=lzo,space_cache,autodefrag  0 1
/dev/sda10 /home btrfs subvolid=260,defaults,compress=lzo,space_cache,autodefrag 0 1
/dev/sda10 /var/cache/pacman/pkg/ btrfs subvolid=262,defaults,compress=lzo,space_cache,autodefrag 0 1
/dev/sda8 /boot ext4 defaults 0 1
/dev/sda9 swap swap defaults 0 0
……

3、/etc/default/grub里GRUB_CMDLINE_LINUX_DEFAULT="rootflags=subvolid=256"后生成grub.cfg。这是告诉内核启动时把subvolid=256当成/。以上所有用id的地方都可以用subvol=名称
设置好root密码--passwd root。然后你觉得差不多就可以重启了

    重启以后,按照自己的喜好配置系统吧!操作和别的文件系统完全一样。大家用df看看硬盘容量,一定会惊奇于大小的:我整个系统包括X、左面环境和日常软件一共只占了1.8G大小!大家肯定还有一个疑问:df显示的total != used+available,前者比后者大了1/8左右,这是为什么呢?还是来看挂载选项:

metadata_ratio=number
Sets the number of data chunks that need to be allocated to force a metadata chunk allocation. By default this is set to 8.

    就是说,默认情况每分配8个data chunk会分配1个metadata chunk,所以那1/8是metadata的大小。难道说btrfs的硬盘利用率只有8/9?不用担心,btrfs会把能放进metadata chunk的小文件放在里面,所以那1/9的空间也是可以存储文件的!而命令

btrfs filesystem balance

可以重新平衡文件分布,如果是raid,那么在多个设备上平衡负载;如果对单设备的metadata进行,就可以平衡小文件的分布。以后可能会自动后台进行metadata的balance。而且鉴于lzo平均2.08的压缩率,磁盘利用率会提高很多,尤其是对于大量的文本配置文件、源代码等。
    再说一说snapshot这个吸引人的特性,snapshot就是依据现有的subvolume新建一个subvolume,有点像OO语言中的引用,对一个subvolume创建一个快照后,两者是平等的;一个文件有引用计数,可以在多个snapshot中被引用,或者由cp --reflink=always创建一个引用(目前cp的reflink不能做到跨subvolume引用,补丁还未合并),当引用数降为零时文件才被删除;和硬链接不同的是,当文件在一个快照中被修改时会新复制一份储存在这个快照中,而不会影响到别的引用,这就是copy-on-write。这样的快照能充分节省空间。我们来演示一下:
    首先,我们要挂载总结点

mount -o subvolid=0 /dev/sdaX /mnt

cd到/mnt,我们创建一个对于rootfs的快照:

btrfs subvolume snapshot rootfs 20120516

建议:

touch 20120516/This-is-snapshot-20120516

注意:btrfs的快照不具有递归性,即如果rootfs中还有二级subvolume,那么快照中不会包含二级subvolume的文件,而是包含一个对二级subvolume的引用,类似于这样:

0----rootfs--------------------------------------------subvol2-----文件a
    |                     |                               ^
    |                     -----------文件夹b--文件c       |
    |                     ---文件d      ^        ^        |
    |                         ^         |        |        |
    |                         |         |        |        |
    --20120516---------------------------------------------

在rootfs中修改文件d、c会复制一份新的,对20120516不可见;而修改a的话在rootfs和20120516中都能看到。
    所以为什么我们之前分了三个subvolume:
1、一般灾难都是/所致,所以不需要把/home也整个备份,而且/home中修改频繁,很容易创造大量新文件,占用空间;
2、能够对/home单独snapshot
3、pkg是pacman的包所在地,一般不需要备份。这样对rootfs快照后pkg不会被打进去,使用pacman -Scc后也不会因为20120516中仍有对其中软件包的引用而导致不能释放硬盘空间。

    灾难恢复也变得很简单了,回滚到上一个/的状态,只要在开机时编辑grub菜单linux项里把rootflags=subvol=rootfs改成rootflags=subvol=20120516就回滚了。开机后如果你发现/下有刚才touch的文件This-is-snapshot-20120516,那么你就成功进入了快照中!
    快照也是可读写的,所以对于/home的快照恢复不需要重新挂载一边,找个地方把/dev/sdaX挂上就能在里面把需要的文件cp出来。当然你想回滚整个/home的状态那么就改fstab好了。
    定期创建和清理不需要的快照是个好习惯!清理快照能解除引用,释放你在当前系统中删除的文件的空间。对于重要文件,还是建议不要完全依赖快照,在别的文件系统或网络上留一个备份为好。

    最后说一下问题和修复的办法,我没有遇到过问题,就是摘录几个方法:
1、mount选项里的recovery会尝试找到上一次的节点,比如写入一个文件一半后断电,ext4下这个文件会损坏,而btrfs你可能会得到这个文件写入前的版本。所有没有执行flush的操作都会导致得到旧版本的文件。
2、btrfsck。btrfs有fsck,但是api和fsck.ext4等不同,所以还没有集成进去,mkinitcpio里也没有。建议在initramdisk里包含这个(mkinitcpio.conf的BINARY="btrfsck"),如果文件系统错误得挂载不了了,在ramfs里执行btrfsck /dev/sdaX
3、AUR里有一个mkinitcpio-btrfs,是方便回滚的脚本。我不太喜欢它的命名风格(当前/叫__active,我叫rootfs的,备份在__snapshot subvolume里,而我放在根节点下),所以我没用。经常回滚的可以参考一下。

    还有几个提醒:
1、备份备份备份!光有回滚不能保证你的数据安全。
2、/boot是独立的,所以没有内核回滚能力,请自行备份内核。
3、(和2矛盾)如果用新版本内核提供的挂载选项挂载过btrfs文件系统,再用老版本内核可能会挂载出错!请仔细看挂载选项后表明的内核版本。

    最后有一个疑问:为什么oracle要研发btrfs呢?当时sun的solaris和linux在服务器领域有竞争(我想他们不会认为bsd有和他们竞争的能力),sun的ZFS是一大法宝,而且采用CDDL发布,使Linux无法使用;oracle一方面闭源了ZFS,另一方面却开发GPL的btrfs,GPL意味着它不能将btrfs私有化。Oracle想什么呢?

参考资料:https://btrfs.wiki.kernel.org/index.php/Main_Page
https://wiki.archlinux.org/index.php/Btrfs
https://wiki.archlinux.org/index.php/In … Btrfs_root
http://www.funtoo.org/wiki/BTRFS_Fun

离线

#2 2012-05-18 15:20:06

phoenixlzx
晩ご飯だよー
注册时间: 2011-08-19
帖子: 1,789
个人网站

Re: AcrhLinux实战btrfs

看来我还是等有了SSD再考虑这个东西。

离线

#3 2012-05-18 16:06:10

YeLee
BOT
注册时间: 2011-08-19
帖子: 661

Re: AcrhLinux实战btrfs

当时有点心动,然后手贱了,最后后悔了。


小白路过,大家给点面子!

离线

#4 2012-05-18 16:51:24

jtshs256
论坛版主
注册时间: 2011-08-19
帖子: 294

Re: AcrhLinux实战btrfs

反正现在 btrfsck 可以修复了,折腾无所谓,不过看起来失去了 online fsck 的能力⋯⋯

离线

#5 2012-05-18 18:51:24

cuihao
所在地: USTC, Hefei
注册时间: 2011-08-19
帖子: 1,222
个人网站

Re: AcrhLinux实战btrfs

btrfsck貌似和一般的fsck不兼容,调用fsck.btrfs会说不支持-a什么的。


Site: CVHC.CC   Twitter: @cuihaoleo   Org: LUG@USTC
AD:  ~欢迎参与志愿计算~

离线

#6 2012-05-18 19:08:29

reverland
root
注册时间: 2012-02-04
帖子: 356
个人网站

Re: AcrhLinux实战btrfs

YeLee 说:

当时有点心动,然后手贱了,最后后悔了。

坚持debian一百年不动摇!


>>>>>>>>>jekyll博客>>>>>>>>>>
<<<<<<<<<更残念的vimwiki<<<<<<<<<
本人vim控,偏偏喜欢lisp

离线

#7 2012-05-19 08:30:27

YeLee
BOT
注册时间: 2011-08-19
帖子: 661

Re: AcrhLinux实战btrfs

debian stable内核有点旧了。


小白路过,大家给点面子!

离线

#8 2012-05-19 10:18:24

sgsdxzy
Light
注册时间: 2012-05-17
帖子: 31

Re: AcrhLinux实战btrfs

cuihao 说:

btrfsck貌似和一般的fsck不兼容,调用fsck.btrfs会说不支持-a什么的。

嗯,是的,我尝试把名字改为fsck.btrfs,也出现了不支持-a的问题。不过ubuntu论坛上有人说slackware-current貌似能解决这个问题?我不清楚。

jtshs256 说:

反正现在 btrfsck 可以修复了,折腾无所谓,不过看起来失去了 online fsck 的能力⋯⋯

嗯,online fsck还在实现中

离线

#9 2012-05-19 13:04:09

cuihao
所在地: USTC, Hefei
注册时间: 2011-08-19
帖子: 1,222
个人网站

Re: AcrhLinux实战btrfs

临时解决方案:

cuihao@cuihao-arch ~ $ cat /sbin/fsck.btrfs
#!/bin/sh

opts=""

for arg; do
    case "$arg" in
      -*)
        continue
      ;;
      *)
        opts="$opts $arg"
      ;;
    esac
done

exec /sbin/btrfsck $opts

网上搜索到的。


Site: CVHC.CC   Twitter: @cuihaoleo   Org: LUG@USTC
AD:  ~欢迎参与志愿计算~

离线

#10 2012-05-19 13:39:29

sgsdxzy
Light
注册时间: 2012-05-17
帖子: 31

Re: AcrhLinux实战btrfs

cuihao 说:

临时解决方案:

cuihao@cuihao-arch ~ $ cat /sbin/fsck.btrfs
#!/bin/sh

opts=""

for arg; do
    case "$arg" in
      -*)
        continue
      ;;
      *)
        opts="$opts $arg"
      ;;
    esac
done

exec /sbin/btrfsck $opts

网上搜索到的。

光这样不行,btrfsck本身没有打进去

离线

#11 2012-06-18 00:01:53

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,368
个人网站

Re: AcrhLinux实战btrfs

我想知道这个怎么加密?

离线

#12 2013-12-26 21:47:53

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,368
个人网站

Re: AcrhLinux实战btrfs

加密已经解决了。加 encrypt hook 就可以。

但是又冒出了新问题:回滚的时候内核会找不到属于它的模块。systemd 挂载不了 /boot 直接进维护模式了……虽然可以进去把当前内核的模块找到并 mount --bind -o ro 过去,但是太不优雅了 :-(

离线

#13 2013-12-26 21:50:51

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,368
个人网站

Re: AcrhLinux实战btrfs

一次启动改变了 685 个节点?共八个文件。挺好的。

离线

页脚