从“快照”到overlay filesystem
需求大概是这样:在一个linux系统上,想跑多个不同应用,这些应用由不同的运维来操作,为了避免互相干扰,希望运维只能看见自己的文件,而看不见别的应用的文件信息。一个常用解决办法就是干脆装多个虚拟机,但是,虚拟机对我们来说偏“重”,比如,多个应用公用的一些动态链接库(比如 libc.so)和配置文件(比如 hosts.conf)就复制了多份,如果原先一个系统在运行时系统文件占了500M的cache,那么现在装了4台虚拟机,就有2G的cache被重复占用了。
怎样才能让系统文件只占一份cache呢?我们首先想到这么个主意:把linux系统装到ext4上,然后做4个snapshot("快照“),这4个snapshot分别mount到4个目录,4个运维chroot到这4个目录里,然后就自己干自己的,干扰不到别人的文件。由于ext4 snapshot的实现机制是让同一个物理block被映射到不同的文件系统里,所以我们觉得,这一个4k的物理block应该就只占4k的cache。
(也许有人要说,这么费劲干嘛,直接把系统常用的动态链接库做4个软链接出来,给4个运维用不就行了?这样做有两个问题,第一,动态链接库以及各种系统文件很多,不可能一一做软链接;第二,也是关键的一点,如果其中一位运维错误操作,例如覆盖写了某个系统文件,那么其他的运维就歇菜了,因为软链接实际指向的是同一个实际文件。)
于是开始考察ext4的snapshot。ext4目前是没有snapshot功能的,但是Amir Goldstein已经开发好了对应的patch(https://github.com/amir73il/ext4-snapshots/),但是目前还没有被收入mainline。粗略看了一下,Amir的patch目前只支持readonly的snapshot,于是我发邮件问“如果改成writable snapshot,代码量大不大?“,Amir回帖表示代码量不大;另外还有别人回帖,推荐不用ext4而是用device mapper提供的thin provision的internal snapshot(http://kernelnewbies.org/Linux_3.2 ,http://lwn.net/Articles/465740/),这样就不用依赖于某一个文件系统(就是如果咱们以后不用ext4了,也可以继续做snapshot)。
鉴于ext4 snapshot不支持writable snapshot,且有7000行的改动之多,且目前都没有进mainline的计划,而device mapper的thin provision已经进了3.2 kernel,且只有5000行改动,且支持writable snapshot,所以。。。转而又考察thin provision。考察基本顺利,做snapshot没有问题,snapshot写入没问题,最后chroot然后编译kernel测试速度也没问题,但是,最后发现一个郁闷的事情:这些snapshot被mount以后,公用的文件在不同的文件系统里各自都要占一份cache,也就是说,明明是一个4k物理block,mount到4个不同的文件系统,就占4 x 4k的内存cache了!
难道是device mapper的问题?于是再试了一下ext4的snapshot,甚至btrfs的snapshot,都一样!这就是vfs的特性:只要是inode不同,即使这些inode指向的是同一个物理block,那么它们的cache都是各自独有的,不共享。
我把这个事儿告诉了coly(@淘伯松)
coly: (石化片刻)唉,我们之前想漏了,snapshot根本不能解决这个问题。。。太郁闷了,测了快两周才发现
我: 想开一点吧,还好是测出来的,而不是上线了才发现——到时候运维找过来“你们的这个方案好像不省内存啊”,然后还得解释,还得回滚,就更被动更狼狈了
coly: 噢,你这样一说,我舒坦多了
最后还是马涛同学(@淘伯瑜)给出了一个方案——overlay fs(http://ovlfs.sourceforge.net/),能把两个目录(甭管是什么文件系统的两个目录,是目录就行)“叠合”成一个文件系统,而这个新文件系统的inode其实还是原来目录里的那个,但是视图已经是“叠合”后的了。
比如,有两个目录,其中一个目录dir1有两个文件,是:
./ab (ino:14)
./cd (ino:16)
另一个目录dir2有三个文件,是:
./apple (ino:23)
./banana (ino:27)
./lemon (ino:31)
最后用
mount -t overlayfs overlayfs -olowerdir=/dir1,upperdir=/dir2 /test/
建立的新文件系统/test/里看上去是这样:
./ab (ino:14)
./cd (ino:16)
./apple (ino:23)
./banana (ino:27)
./lemon (ino:31)
注意,inode还是那些inode,但是他们“凑一块儿了”,而且,这个新文件系统是可写的,即使覆盖写了某个文件,也只影响upperdir(例子里的dir2)的内容,而lowerdir(例子里的dir1)没有任何影响。这样,我们就可以把linux系统根目录当成lowerdir,而每个运维自己的系统当成 upperdir ,某个运维的错误操作就不会影响其他人了。
感谢马涛同学的推荐,目前这个还没有进mainline的overlay fs非常契合我们的应用。
相关文章
- ext4 bigalloc 答疑 - 02 21, 2013
- 修复ext4 aio bug一个 - 01 15, 2013
- 修复ext4 bug一个 - 12 25, 2012
普通的虚拟化可能有点重了,咋不考虑OpenVZ这种伪虚拟化呢?
用过 / 自制过 LiveCD 的应该知道 aufs / unionfs 甚至更早之前的事情.
没错!马涛同学一开始提醒我们的就是union mount,我们顺藤摸瓜才找到的overlay fs
问题是overlay fs貌似支持的kernel版本很低啊。。。
没有吧,Miklos Szeredi 同学已经把overlay fs backport到 3.2.0-rc6 内核了
git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
openvz和lxc,我们都考察过,它们都相当于“namespace + cgroup“,但是,“节省公共文件占用的内存”,这个它们目前都做不到(也可能是暂时还没做到),所以,还需要overlay fs这个补充方案
给力。