玩转ZFS文件系统
Send to KindleZFS是sun建立在solaris上的号称终极的文件系统,被opensolaris开放,被FreeBSD所推广使用,所以普通用户最常接触的ZFS系统就是open solaris 11和 基于FreeBSD的FreeNAS 8,对于ZFS文件的练习和应用我也是基于这两个系统。
首先再回忆一下ZFS的优点:
- 软raid,支持raidz1/raidz2即raid5/6,方便扩展,不需要特定的支持raid的硬件,比如南桥,raid卡,极大地降低了成本和复杂度。
- raid的存储设备无顺序,他原本是通过文件头和文件尾在硬盘的头尾处来标定盘序号,用户无关性,只需要将盘加入一个存储池,至于其中的raid是怎样的顺序是不需要担心的。
- 设备无关性。只与容量相关,与使用的什么设备无关,可以ssd和hd甚至闪存卡之间建立raid,也可以在一个硬盘内部的分区和其他存储设备间建立raid
- 快速扩容,替换故障硬盘,自动重建。
- 支持高级缓存,多级缓存。而硬raid卡要达到同样的性能需要付出数倍的价格。
- 只能扩大,增加规模,不能缩小、删除存储池内使用中的部分设备
ZFS是把存储设备建立成为一个存储池,在这个池中,还可以建立更小的池。每个同等级池之间的关系可以使各种raid关系;而子父级之间的关系,就和 存储设备和存储池之间 一样。可以在下图中清楚看到这种管理方式是如何存在的。
命令 zpool = zfs
一般过程是先查看有哪些设备连接了,FreeBSD或solaris中的linux命令
$ fdisk -l
是无效的,要列出连接的硬盘,我选择
$ format
命令,记录下所有设备编号,如VMware下就是c5t0d0,c5t1d0,c5t2d0,….
查看zfs状态的命令
$ zpool status
可以看到系统内所有存储池状态和硬盘健康度,可以在status后面加 -x 参数看所有存储池是否健康
类似的可以查看存储池总容量(包括冗余)情况的命令
$ zpool list
用来搭配使用的
$ df -h poolname
检查容量实际使用情况
zfs建立一个存储池的命令是
$ zpool create poolname raidz1 c5t0d0 c5t1d0 c5t2d0
将会把c5t1~3d0 3个硬盘建立一个名字为poolname的raidz1模式(raid5)的存储池。
删除销毁一个存储池命令是
$ zpool destroy poolname
将zfs的存储池挂载和卸载的命令,如同mount/unmount的是
$ zpool import/export poolname
这个一般是在恢复日志历史镜像等应用时使用。也可以恢复被destroy的存储池,使用
$ zpool import -D poolname
要看存储池的实时读写状态命令
$ zpool iostat 1
重中之重的replace命令,
$ zpool replace poolname c5t0d0 c6t0d0
就是将接入但没使用的c6t0d0替换了正在使用的c5t0d0,这时使用zpool status应该会看到这两个盘正在replacing,或者rebuild,这在替换报错error/fault的硬盘,或者使用更大的容量替换老硬盘的时候都有用。
当一个raid内所有硬盘都替换为新的更大容量的硬盘后,可以使用
$ zpool set autoexpand=on poolname
开启存储池自动扩展的属性(默认为禁止),或
$ zpool online -e poolname c6t0d0
对一个已经存在的设备使用online命令来达到扩容的目的,再次zpool list查看容量应该可以看到真个raid容量已经扩大了。
其中online命令对应的是offline,zfs中常这样使用
$ zpool offline poolname c6t0d0
当然zfs支持raid中的热备份,可以在create的时候添加spare设备,例如
$ zpool create raidz1 poolname c5t0d0 c5t1d0 c5t2d0 spare c6t0d0
c6t0d0就成为了热备份设备,要删除这个热备份设备(或日志,高速缓存),就要使用命令
$ zpool remove c6t0d0
而对应的zpool add命令却使用很有限,因为这个add只能在现有容量上扩充,也就是加入现有的存储池形成raid0,这很有风险,比如poolname中有c5t1~3d0 3个硬盘形成的raidz1 容量为20G的存储池,使用
$ zpool add -f poolname mirror c6t0d0 c6t1d0
这条命令的意义就是 先将c6t0d0 c6t1d0两盘镜像即raid1,例容量15G,再加入poolname中和已有的c5t1~3d0 raidz1的20G容量再raid0,衔接后面,之后存储池poolname中的总容量就等于20G+15G =35G。如果一个盘坏了,c5t0d0坏了,就会对前面一个raidz1形成影响,变成degraded降级状态,后面一个镜像的c6t0d0 c6t1d0则没有影响。如果后面的两个不是镜像,而是raid0模式,如果一个坏了offline,直接就导致这个raid0失败不可访问,间接的导致整个存储池不可访问,哪怕这个存储池中有一部分的容量自身有备份。

所以add命令必须搭配 -f 参数,意思是强制添加容量到存储池后面,加上zfs只能增加容量不能缩小的特性,为了保险起见,所有add加入的容量必须自身足够安全(比如自身就是raid),否则一旦损坏会出现上面这样的导致所有存储不可访问的问题。这个风险你应该在使用add命令的时候就非常清楚。zfs中不推荐使用raid0模式,除了万不得已。
最好的最安全的扩容就是在raidz1或者raidz2(raid5/raid6)基础上,用大容量设备replace旧的小容量设备,等重建替换完成后,挨个把存储池内所有存储设备升级替换,所有完成后使用前面的扩容命令自动扩容。
zfs文件系统除了方便扩容,方便管理,安全简单以外,当然性能也同样不能太低。而一些朋友常常争论,究竟raid 0+1还是raidz1/raidz2更快,我觉得是没有意义的,因为常常最终管理的存储的容量和速度是成反比的,只要安全,访问速度快慢就交给缓存来解决。zfs在更新数个版本后,缓存管理已经非常优秀了,基本上在只有内存做缓存的系统上,除去基本的4G RAM系统最低要求,每增加10G常用数据,就要增加1G RAM来保证命中和速度,比如后面是100G的常用数据,那么就需要100/10+4G=14G内存来保证较高的读取速度。内存价格偏高,且不容易扩展的时候,就出现了使用SSD固态硬盘来做缓存的技术,形成了CPU->RAM->SSD cache->HDD ZFS的三层结构。在FreeNAS中这点做得很好,设置很方便,有文章指出,4G系统内存下,网络访问速度约为400Mbit/sec read + 300Mbit/sec write,而8G内存+64G SSD的缓存结构下,可以达到900Mbit/sec read + 600Mbit/sec write,跑满千兆网络,同时iSCSI性能飞升,生产环境中也应该这样搭建使用。命令也很简单,只需要在create的时候增加cache SSD0,也可以单独使用命令
$ zpool add poolname cache SSD0 SSD1
来增加一个或多个缓存,此缓存设备可以通过前面提到的remove命令轻松删除。
到这里已经差不多了,对于存储池内数据的完整性,通过命令
$ zpool scrub poolname
达到校验的目的,这一般会花费很长的时间,可以通过zpool status查看校验进度,最好在硬件出现问题,解决后都校验一次以保证一切正常。
观察近两年的发展,FreeBSD的活跃度已经渐渐赶上Linux的开发速度了,相互之间的借鉴也越来越多,而在此之上的solaris也被广泛使用,作为数据服务器的首选。
更多的更详细的资料,就要查看oracle的官方教程了,Oracle Solaris ZFS 管理指南

很惭愧,没有看懂这篇文章,只是知道大致的意思,但如何操作等等,都没有看明白
2012-04-20 09:30博主你好,我现在的生产环境中是使用Solaris系统,4块3T硬盘组成的RaidZ1,打算增加一块SSD作为cache,请问SSD的选择上应该侧重于哪方面的性能?是连续读写,随机读写,还是IOPS?
2013-03-08 12:54对读缓存就用iops高的,弥补机械硬盘的不足,一般来说只要iops高,持续读写性能就不会太差。生产环境一定要考虑寿命,有条件尽量选用SLC颗粒。预算所限,另外只一块SSD cache就读取部分的cache即可。
2013-03-08 13:24zfs的cache可以做读和写两部分的缓存,有条件可以选择两块SSD raid1的写缓存盘 和 一块SSD做读缓存盘。这会让你存储性能大幅提升。
感谢回复.
2013-03-12 12:00ZFS的写缓存应该就是ZIL日志设备吧?
预算确实有限,是不是可以这样来搭配:选择一块容量较大(比如256G)的MLC芯片的消费级SSD来做读缓存,另外用容量较小的(64G)的SLC芯片的SSD做写缓存?
嗯,其实64G SLC价格不菲,容量偏小,非关键领域不如考虑用raid1的带足够保修的MLC颗粒的SSD做ZIL,坏了就换,3-5年后SSD价格更低了,升级就行了。
2013-03-12 12:05读缓存L2ARC选择类似,容量越大命中率越高,平均性能越高。