2.5 磁盘的管理方式
用户也好,权限也罢,它们总是要有一个证明自己的天地;文件也罢,程序也好,它们总是得有一个安身立命的家园;即便Linux自己也必须得有自己的栖身之所。那就是磁盘。其实Linux对磁盘的管理十分对得起两个字:“不赖”!
2.5.1Linux的文件系统
只要是磁盘就得格式化,好像已经是天经地义的事情了,几乎没有人去问为什么。很多有经验的人在似乎都有个这样的经历,就是风风火火的从朋友那里借来了一张装满高清“A”片的移动硬盘,暗爽过后还想留下一些待以后慢慢品味,可是总有那么一些质量比较好的片子(尺寸超过4G)复制失败。追问原因还往往被高手们嘲笑:“都什么年代了你还用FAT32,赶紧换NTFS吧”。我想这个时候你就不得不追问一下,为什么FAT32不行而NTFS却能行吧?
因为它们是不同的文件系统,功能不同,能力不同。FAT32是在Windows95时×××始采用的文件系统,到现在都有人在用(比如U盘),可以说是伴随着我们成长的文件系统。FAT是File Allocation Table的缩写,从字面意义上就能看出这是一种类似表格一样的文件系统。由于其用于描述文件大小的属性是一个32位的值,导致其能够支持的单个文件最大不能超过4G。而NTFS是微软专门为NT系统设计的,单个文件最大可以达到2T。现在最为常用的Windows XP和Windows 7都支持NTFS。至于NTFS是怎么管理文件的有点不太好说,因为微软一直当它是个“秘密”。
Linux也有自己的文件系统格式,被称为ExtN(N=2、3、4)。如果要追溯ExtN的起源,其实要比FAT32和NTFS都要古老,也就是我们前面所说的基于inode的文件系统。如前面所述,ExtN文件系统必定要包含inode数据结构来代表一个文件,并且存储这个文件的各种属性和权限。至于实际的数据则放在data block块区中。除此之外,ExtN文件系统还有一个超级块区(superblock),用于记录整个文件系统的整体信息,包括inode与data block的总量、使用量和剩余量。
data block与inode一样,每一个都有一个唯一编号,inode只需要记录这些编号,就能够定位整个文件的任意一段数据。我们假定有一个编号为3的inode,它所代表的文件的数据被放置在编号为2、5、6、8、13和20的这几个data block中。那么读取这个文件的过程则如图2.4所示。采用这种数据存取的方法的文件系统被称之为“索引式文件系统”。它与伴随着很多人成长的FAT32有什么不同呢?图2.5对比了这个过程。
通过对两个图的比较,我们可以清晰的看出,ExtN通过inode能够一次性获得文件数据所存放的位置,可以据此来安排磁盘的阅读顺序,尽量保证在磁盘只旋转一圈的情况下将所有内容读出来。而FAT32则只有将对应的data block读入之后才知道下一个data block在什么地方。如果一个文件的data block比较分散的话,将很难保证在磁盘只旋转一圈的情况下读取全部数据,有时候甚至要多转很多圈才能读完数据。
这就是我们非常熟悉的“磁盘碎片”问题。由于长时间的对文件进行创建、删除、读写,很难保证同一个文件的data block的位置相邻。而由于FAT32的读写特性,在data block不相邻的情况下读写性能会极具下降。所以为了提高Windows系统的磁盘性能,经常性的做“磁盘碎片整理”是非常有必要的。
而对于Linux这种文件系统,则基本上不需要进行磁盘碎片整理。而且你也基本上找不到类似的工具。但是Linux系统经过长时间使用之后,还是会有文件数据过于分散的问题的。即便能够做到很好的规划,但是对性能多多稍稍还是会有一些影响,只是没有使用FAT32的Windows那么严重罢了。所以,一个使用时间很久的Linux系统也会因为磁盘碎片问题而变慢,这也是事实。只是不需要太过在意它。
图2.4 ExtN文件系统读取数据过程示意图
图2.5 FAT32文件系统读取数据过程示意图
2.5.2 磁盘的基本操作
在前面的小结中介绍过几个最常用的文件操作命令:ls、cd、cp、rm和mv。虽然它们也都是作用在磁盘上,但是它们面向的对象更为高级一些,属于文件范畴的。而我们现在要介绍的是稍微低级一点,面对是的文件的载体——磁盘的一些基本操作。最常用的是:df、du、dd、fsck和mount。
df命令用于查看系统中所有磁盘的整体使用量。在我们的测试系统中能够得到如下所示信息:
Filesystem 1K-blocks Used Available Use% Mountedon
/dev/mapper/VolGroup-lv_root
51606140 5587240 43397460 12% /
tmpfs 250860 272 250588 1% /dev/shm
/dev/sda1 495844 31891 438353 7% /boot
/dev/mapper/VolGroup-lv_home
9877432 1681704 7693968 18% /home
可见df命令的输出还是比较清晰的。但是有两个概念可能需要解释一下,就是这里所说的“Filesystem”和“Mounted on”。如果要翻译成中文(很多人的机器中可能显示的字段名)则是“文件系统”和“挂载点”。
这里所说的“文件系统”与我们之前所说的操作系统中的文件系统的概念有点不尽相同,着这里更多的含义指的是磁盘分区。之所以叫它是文件系统,是因为每一个磁盘分区都是一个文件系统的具体实例,如果套用面向对象的说法就是,类和对象。诸如ExtN这样的就是类,而具体的磁盘分区就是这个类的对象。至于“挂载点”则比较有趣,它是某个具体的目录。
从df每一个行的输出上看,难道具体的磁盘分区会与某个具体的目录有关?事实的确是这样的。前面也是说过,Linux没有Windows中的C盘、D盘的概念。精通Windows的同学都清楚,Windows中的分区会有一个盘符与它对应,在分区中的文件和目录的组织结构就像一颗树一样,树根就是盘符+“:”。Linux组织文件和目录的方式最终也能被看作是一棵树。但是由于没有C盘、D盘的概念,更没有盘符一说,于是就特意规定了一个总的树根叫“/”,而具体某个分区的树根就从某个目录开始。至于不同的分区应该从哪个目录开始这个就没有明确的规定。其实不规定也就是有规定,即你可以随意指派。而具体指派哪个分区与哪个目录对应,就由mount命令来指定了。之后只要访问哪个目录里的任何文件或目录,都是对具体的分区进行访问了。而这个目录则被称为“挂载点”。
根据df命令的输出内容可以看出,Linux文件中的总树根“/”与“分区”/dev/mapper/VolGroup-lv_root相关联,而/dev/shm目录与“分区”tmpfs相关联,/boot目录与分区/dev/sda1相关联,……。这些“分区名”都什么含义呢?其实在这些所谓的分区中,只有/dev/sda1才是真正的磁盘分区,而这个名称则是这个磁盘分区的“设备名”。在Linux系统中,/dev目录下的所有文件都与一个具体的设备有关,有物理的,也有虚拟的。而sda1这个就是一个物理的设备。它对应系统第一块串口硬盘的第一个分区。那么如果是第二个分区呢?sda2,第三个是sda3……,而对应整块硬盘的则是sda。由此递推,第二块串口硬盘,应该是sdb,第三块应该是sdc……。而/dev/mapper/*这些又是什么呢?这个就是虚拟的设备了,它实际上是逻辑卷。有关逻辑卷的概念我们稍后在说,现在你只要知道它是虚拟的磁盘分区就行了。不过更奇怪的是tmpfs,这个设备文件在什么地方呢?答案是没有,因为它不对应任何设备。它实际上是真正的文件系统名称。而这个文件系统是在内存中虚拟的,与具体的硬盘无关,所以也没有具体的设备。于是在df的输出中所幸就与“类名”代替了。这样的文件系统还有很多,比如procfs、sysfs等,本书会有专门的一章来介绍这些特种文件系统。
df命令本身就没有什么好继续再介绍的了,上述的一些概念远比df本身要重要很多,这个是大家应该更加注意的。对于/dev目录下的那些文件,本书不会逐个的去讲述它们都代表谁。毕竟每个人的系统都不同,所以也没法说,你没看到你怎么信我呢?比较好办的办法是问百度或谷歌,它们是你学习Linux必不可少的工具。好了,我不能再说多了,因为这样你们都会不买我的书而逛百度去了。
df命令是用来观察总体磁盘使用量的,要观察局部使用量,需要使用du命令。df命令可以通过读取磁盘的superblock来实现,而du命令则不同,它要搜索所有的inode来计算局部数据,所以du命令的执行效率,经常要比df差很多。
从严格意义上来讲,dd命令应该不属于管理磁盘的命令,因为在联机帮助中说它的功能是“convert and copy a file”。但是如果你想要直接读写磁盘的每一个扇区,或者镜像整个磁盘,dd命令则是非常好的选择。通常dd命令的格式如下:
dd if=input_file of=out_file
从这个基本用法,如果像联机帮助中说描述的,复制一个文件,可以使用类似这样的命令:
# dd if=/etc/bashrc of=./bashrc
这个命令与cp /etc/bashrc ./bashrc是等价的。其实“if”和“of”这两个参数也不用给定,会有默认值。“if”的默认值是标准输入,“of”的默认值是标准输出。如果要模拟cat命令,可以使用这样的命令:
# dd if=/etc/bashrc
根据前面的讲述的内容,具体的硬件设备在/dev目录下会由具体的文件与之对应,比如/dev/sda1。如果要制作第一个串口磁盘第一个分区的镜像文件,可以使用这样的命令:
# dd if=/dev/sda1 of=./sda1.img
需要注意,执行上面的命令时,输出文件所在的分区必须大于sda1分区,至于为什么我想你懂的。如果还希望对生成的镜像文件压缩一下,可以使用这样的命令:
# dd if=/dev/sda1 | gzip -9 > ./sda1.img
按照这个思路,我们将整个磁盘都做一个镜像呢?
# dd if=/dev/sda | gzip -9 > ./sda.img
如果要恢复这个磁盘的内容,就可以这样:# gzip -dc ./sda.img | ddof=/dev/sda
通过这两条命令,大家想到了什么?这个是不是与我们在Windows下经常使用ghost非常像呢?感觉塞门铁克公司的老大应该找块豆腐撞死。而dd命令还不止这点本事,它还能指定读写数据量。比如bs和count这两个参数,能够指定依次读写的自己数和读写次数,这样就能够指定读写数量了。比如我要备份磁盘的主引导记录,可以这样:
# dd if=/dev/sda of=./mbr.img bs=512 count=1
这要求值读取sda磁盘的首个512个字节的信息,也就是第一个扇区的内容,将它保存到mbr.img文件。对mbr内容感兴趣的同学,可以使用反汇编工具,将这个文件反汇编掉,就能知道计算机是怎么启动的了。
使用dd命令能够做的事情还有很多,比如销毁磁盘数据、测试磁盘读写速度、修复磁盘等,为了方便你使用,我将这些技巧列下来:
# dd if=/dev/urandom of=/dev/sda1
# dd if=/dev/zero of=./test.file bs=1024count=1000000
# dd if=./test.file bs=8k | dd of=/dev/null
# dd if=/dev/sda of=/dev/sda
看完这些,我觉得你们更会认为赛门铁克公司的老大应该买块豆腐撞死。特别说明一下/dev/urandom、/dev/zero和/dev/null这三个虚拟设备设备文件非常有用。urandom代表随即数,每次读入的数据都不会相同;zero代表0,每次读入的数据都是0;而null主要面对写,相当于是一个黑洞一样,无论写什么都会消失得无影无踪。
不知道通过我上面的介绍,大家是否已经理解dd在磁盘管理中的作用了呢?既然到了这个份上,理不理解我也管不了了。生活还得继续,我们的内容接着往下走,该说一下fsck了。
fsck一般我们很少手工执行,基本上都是在系统启动阶段就执行了。至于它是什么作用则非常简单,与Windows的scandisk一样,对文件系统的损坏进行修复。需要注意,fsck只能对文件系统的损坏进行修复,对磁盘的损坏它是没有办法的。后面我们会有单独的章节来介绍fsck的工作原理,这里就不做复述。具体的使用方法就是:
# fsck -t 文件系统设备名
比如:
# fsck -f -t ext3 /dev/hda3
其中参数“-f”要求进行强制检查。如果不增加-f选项,在没有报错的磁盘中是不会做检查的。至于磁盘什么时候会报错呢?一般就是非法关机的时候了!
期待已久的mount的终于登场了。前面已经讲过“挂接点”是个什么东西了,相信大家还在为Linux这种“怪异”的设计而啧啧称奇呢。但是早已用惯Linux的我反倒觉得Windows的设计非常奇怪。相比之下,Linux的方式更为灵活。就比如在Windows下有一个软件必须在D盘下的某个目录中读取文件,而这个软件若是在一个没有D盘的系统中就无法执行了;相反的,在Linux下,只需要特意创建一个目录即可,如果需要单独的磁盘分区来存储它,使用mount命令指定给它就好了。
虽说mount命令听起来有点神奇,但是使用起来却是非常简单。一般的用法是这样的:
# mount [-t 文件系统] 设备名称挂接点
比如我们要将系统中第二块串口硬盘的第一个分区(如果有的话)挂接到/data目录下,可以这样用:
# mount /dev/sdb1 /data
或
# mount -t vfat /dev/sdb1 /data
怎么样,够简单的吧?对于第二种用法很多时候“-t”参数是多余的,因为类似ext2、ext3这样的ExtN类的基于inode的文件系统,都是都有超级块的。利用超级块就能够了解到具体的文件系统。所以第一种用法在大多数时候都会成功。而第二种用法多数用于挂接Windows分区时使用,因为这些文件文件系统不具备超级快。
其实挂接磁盘分区还只是mount命令的最平常的一种用法。由于Linux使用设备文件来描述一个设备,那么如果有一个实际的文件中的内容与在某个磁盘设备文件中的读到的内容一致,那么这个实际的文件也能够挂接进来。就比如我们之前使用dd命令创建的sda1.img文件(未压缩的),就可以利用这样的命令来挂进到一个目录上:
# mount -o loop ./sda1.img /mnt/sda1
这样你就会发现/mnt/sda1目录下的内容与/boot目录下的内容相同(别忘了之前df命令的输出)。以此类推,我们下载到的*.iso文件也可以使用同样的方法挂接到某个目录上直接访问了。例如:
# mount -o loop ./CentOS-6.4-x86_64-bin-DVD1.iso/mnt/centos
看到这里是不是觉得Windows下那些虚拟光驱软件的作者们都开买块豆腐撞死了?
在这种mount的用法中,比较重要的是“-o”命令选项,这是个mount比较灵活的一个选项,有很多可选参数。比如“ro”说明挂接的磁盘是只读的、“rw”说明挂接的磁盘是可读写的等等。而loop则说明要挂接的文件是一个虚拟设备,而这个虚拟设备是环形的设备。为什么是“环形”呢?想想硬盘、光盘、软盘等都是什么形状就行了。还不知道?圆形的啊!
与mount相反的操作就是卸载了,使用umount命令。它的操作更加简单,给定挂接点目录或具体设备就行了。比如:
# umount /data
或
#umount /dev/sdb1
如果你的系统中有这些设备,则这两种方法是等价的。
其余的有关进行磁盘分区和格式化的命令就不做详细介绍了。因为很多人连Windows下这样的工具怎么用都还搞不清楚,可见它们都是很少用到的东西。为了满足一份同学的好奇心,我们在这里只说一下它们的名字。
用于磁盘分区的命令是fdisk,这与Windows或DOS下的命令名是一致的。比fdisk更好用一些的分区工具是cfdisk,Cent OS中有提供。而对磁盘做格式化的则不是format命令。在Linux是下mkfs.*命令。至于*是什么,取决于你格式化成什么系统。比如要格式化成ext3文件系统,就应该是mkfs.ext3。如果想了解系统中都对那些文件系统支持这样的命令,直接到/sbin目录下查看就是了。而更为通用的格式化命令则是mkfs,具体如何使用,查看联机帮助吧。这类工具与之前介绍的那些磁盘工具也是一样的,可以对某个磁盘中的一个具体文件进行“分区”和格式化。
2.5.3 /etc/fstab文件
现在大家已经了解到了Linux磁盘的一些基本管理方式,也了解了“挂接”这个新鲜玩意儿。Windows是怎么操作的我们不是很清楚,但是在Linux启动之后,其文件布局能够像你所见到的这样都是经过一步一步的挂接来完成的。决定让磁盘的各个分区具体要挂接到哪个目录是由/etc/fstab文件所决定的,所以这个文件是Linux系统中十分重要的文件,一旦损坏或丢失,系统将无法正常启动。所以掌握这个文件的格式并能手工恢复它,将是成为Linux系统管理员的必修课程。这个文件(/etc/fstab)在我们的测试系统中如下所示:
#
# /etc/fstab
# Created by anaconda on Sat Mar 17 05:12:212012
#
# Accessible filesystems, by reference, aremaintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8)and/or blkid(8) for more info
#
/dev/mapper/VolGroup-lv_root / ext4 defaults 1 1
UUID=ec11a28b-9bf2-4f7e-95dc-2b7ccd5992ca /boot ext4 defaults 1 2
/dev/mapper/VolGroup-lv_home /home ext4 defaults 1 2
/dev/mapper/VolGroup-lv_swap swap swap defaults 0 0
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
我们可以清楚地看到,这个文件一共分为6个字段,分别是:
l设备文件、磁盘卷标或者UUID
l挂接点
l文件系统类型
lmount命令的-o选项参数,defaults不给定-o选项时的行为
l是否使用dump命令备份,0代表不做,1代表每天备份
l是否使用fsck命令检查磁盘;0代表不检查,1代表最早检查(一般只有树根“/”是1),2也是要检查,只是比1要晚(除树根之外的一般都使用这个)
在第一个字段中,我们看到了一些在df命令中出现的“分区”,而有一些则没看到过。其实使用“df –a”就可以查看更多了。而比较让人困惑的是/dev/sda1确不见了,但是能明显看出来是“UUID=ec11a28b-2bf2-4f7e-95dc-2b7ccd5992ca”这个设备。使用命令blkid命令就能露出真面目了。实际上在这里直接写/dev/sda1也是没有问题的。
虽然/dev/sda1找到主了,但是还有一个分区在df命令的输出怎么也找不到,那就是类型为swap的这个分区。这个是什么呢?这个是交换分区!交换分区是什么概念呢?与Windows的页面文件是相同的概念!
所谓的页面交换文件,实际上就是虚拟内存管理时要使用的内存置换文件,就是用来扩展虚拟内存空间的。当然,也是拖慢系统的罪魁祸首之一。需要注意,如果你使用的是32位的系统,而且已经配备了4G的内存,那么就没有必要给Windows分配页面交换文件(在没有开启PAE模式的情况下)。Linux下也有这样的规矩,只是将页面交换文件变成交换分区了。
创建交换分区可以使用fdisk命令,格式化它使用mkswap命令。这个似乎并没有逃出我们之前所掌握的一些知识。但是到了具体挂接的时候就不一样了,它不是挂接的,即不是使用mount命令来用的。取而代之的是使用swapon命令。如果需要关掉某个交换分区,则使用swapoff命令。
此外,根据我们之前的经验,普通文件也是能够成为“交换分区”的(还记得前面讲的虚拟光驱吗?),我们所幸就叫它交换文件好了。方法就是使用dd命令来创建一个空的文件,然后使用mkswap命令来“格式化”它。比如创建一个1G的交互文件,可以这样:
# dd if=/dev/zero of=/tmp/swap bs=1Mcount=1024
# mkswap /tmp/swap
至于接下来该怎么做,我想你懂的。
2.5.4 逻辑卷
在前一小节中我们留下了一个小尾巴,说/dev/mapper/*这些都是逻辑卷。而具体逻辑卷是什么就没有继续说,主要是因为这个小尾巴其实并不小,一不小心可能夹到尾巴。
1.什么是逻辑卷
那么到底什么是逻辑卷呢?这个可能得需要一个比较实际的场景来解释一下,正好还有一个。
前几天我有一个同事,在自己的电脑中与他的Windows并行安装了一个Ubuntu。他在使用Linux的时候总是显得很小气,只给他的Ubuntu分了10G的硬盘空间,并划分了三个分区分别给了“/”、“/home”和swap。树根“/”分配2G的空间,“/home”分配了7G,swap为1G。这样的分配方法还是比较专业的。只是没过几天他就遇到了麻烦。他想用这个Linux系统来定制一套Android系统,于是就需要下载到Android的全部源代码。但是没想到Google实在是大方,7G的磁盘空间不够装Android的源代码。好了,我想问问各位同学,你遇到这样的问题要怎么做?
按照我们前面掌握的知识可以这样做。首先再从硬盘中划分一个更大的分区出来,比如100G;然后再将这个分区格式化成Linux的文件系统,并将/home目录下的内容全部复制到新的分区;最后修改/etc/fstab文件,让新的分区成为/home。重启之后就大功告成了。看来问题解决的非常好,Linux的灵活性显然不一般。但是如果觉得100G给的太多了呢,Windows又不够用了怎么办?难道再重复上述动作?天哪,复制文件是要花很长很长时间的,尤其是这种源代码的东西,无数的小文件。
好了,逻辑卷就是来解决这个问题的,它能够弹性的调整文件系统的容量。从理论上说,逻辑卷就是在磁盘分区和文件系统之间增加了一个逻辑层。这样,当文件系统的容量觉得不够用时,可以向逻辑卷中增加新的分区来实现扩大容量的目的;而当发现文件系统过大而有磁盘浪费的时候,可以选择去除一些基本没有使用的磁盘分区来达到容量的目的。在Linux系统中实现逻辑卷更能的是LVM,即Logical Volume Manager,逻辑卷管理器。
2.基本术语与原理
在进一步讲述逻辑卷之前,我们先了解一下它的基本术语。
lPhysical Volume,PV,物理卷
物理卷就是具体的硬盘分区,或者与硬盘分区具有相同功能的设备,比如raid等,是LVM的基本存储单元。但是与基本的物理存储介质,比如普通的硬盘分区等,物理卷还要包含与LVM相关的管理参数。
lVolume Group,VG,卷组
卷组类似于非LVM系统中的物理硬盘,由多个物理卷组成。可以在卷组上创建一个或多个LVM分区。
lPhysical Extend,PE,物理扩展区
每一个物理卷被进一步划分成被称为物理扩展区的基本单元,换句话说PE是LVM使用的最小存储区,与物理磁盘中的“扇区”或文件系统中的“簇”的概念基本相同。LVM的默认PE大小是4M,每个卷组最多仅能含有65534个PE。所以,一个卷组的最大容量就是4M*65534=256G。如果改变PE的大小,就能够改变卷组的最大容量。
lLogical Volume,LV,逻辑卷
最后我们说道正题上了,就是逻辑卷。这个逻辑卷就是在卷组之上再进行切分,与在物理磁盘上继续划分分区是一样的道理。但是逻辑卷的大小必须是PE的整数倍。这就是LVM能够弹性调整逻辑卷容量的秘密所在。需要增加容量,就增加PE;需要减少容量,就减少PE。LVM的构成原理见图2.6所示。
图2.6 LVM的构成原理
到了具体的逻辑卷上,就可以应用mkfs命令进行格式化了,如此以来就能够使用mount命令挂接到系统中了。
构成原理现在算是搞定了,但是对于一个逻辑卷可能会对应到多个物理分区上,那么在向硬盘中写入数据的时候是怎么操作的呢?目前有两种模式:
l线性模式(linear):即逐个物理分区使用。比如一个逻辑卷占用了/dev/sda1和/dev/sda2两个分区,那么首先写/dev/sda1,直到满了之后才会使用/dev/sda2。
l交错模式(triped):这个就将一笔数据拆成两个部分,分别写入/dev/sda1和/dev/sda2。这个与RAID 0很像。如果使用/dev/sda1和/dev/sdb1这样的组合来做逻辑卷,有相当于一份数据用两个硬盘来写,理论上是能够提升读写效率的。
需要注意,虽然交错模式的逻辑卷有点像RAID,但是它的最终目的还是用于磁盘容量的弹性可调的。如果要关注性能,还是直接使用RAID比较好。而且triped模式的逻辑卷与RAID 0是类似的,即当某个分区挂掉了,那么你的数据也会跟着灰飞烟灭的。所以逻辑卷的默认工作模式是linear的。
3.基本操作
Cent OS已经默认支持逻辑卷了,所以如果选择了Cent OS的同学,现在就已经在使用逻辑卷了。但是如果你选择了Ubuntu这样的发行版,就没有这么幸运了,因为Ubuntu并没有提供这方面的支持。但是也不要紧,我们可以手动安装。
首先,逻辑卷必须有内核支持才能工作。所以必须保证你所使用的内核已经开启了的逻辑卷的支持(好在大多数主流发行版的内核都支持);其次,需要安装lvm2软件包。当这些都准备妥当之后,就可开始具体的工作了。
第一步就是准备磁盘空余空间(PQ绝对是个好工具),硬盘多的同学可以考虑利用第二块硬盘。然后在这些准备好的空余空间中划出几个分区来,并设置分区类型为Linux LVM(分区标志是8e)。我们这里正好有一个块20G的老硬盘,我们将它划分了4个分区,平均每个分区5G。
第二步是创建物理卷。与物理卷相关的命令有:pvcreate、pvscan、pvdisplay和pvremove四个。具体都提供那些功能,相比通过名称都能了解到。我们将刚刚划分的4个分区都设置成物理卷,执行这样的命令:
# pvcreate /dev/hdb1
# pvcreate /dev/hdb2
# pvcreate /dev/hdb3
# pvcreate /dev/hdb4
或
# pvcreate /dev/hdb{1,2,3,4}
显然后一种的风格更加简便,所以我们后面的所有操作都将采用这种风格。
第三步就是创建卷组VG。操作卷组的命令有:vgcreate、vgscan、vgdisplay、vgextend、vgreduce、vgchange和vgremove。创建一个新卷组可以执行类似这样的命令:
# vgcreate /dev/hdb{1,2,3} NewVolGroup
我们知道卷组是由多个物理卷构成的,现在我们将/dev/hdb1、/dev/hdb2和/dev/hdb3做成一个名为NewVolGroup的卷组,留下的那个用于放在后面说明如果动态增加或减少容量用。在卷组中额外添加或删除物理卷的命令是vgextend和vgreduce。在创建创建卷组的这一时刻,可以给vgcreate命令传递“-s”选项指定物理扩展区PE的大小,比如16M。可能有同学会觉得设置较大的PE会导致磁盘的浪费。其实不然,PE与磁盘的最小存储单元“扇区”或“簇”不同,他只是LVM用于进行动态伸缩尺寸的一个最小分配单元,而在真正存储文件的时候,还是会利用磁盘本身的最小存储单元。
第四步是创建逻辑卷LV,就相当于对卷组这个大磁盘进行分区。与逻辑卷LV有关的命令有:lvcreate、lvscan、lvdisplay、lvextend、lvreduce、lvremove和lvresize。出于方便考虑,我们将整个VG只划分为一个LV,使用命令:
# lvcreate -l 3842 -n lv_data NewVolGroup
在这个命令中“-l”选项说明分配的PE数量,“-n”选择则为新的LV命名。本例中3842正是我们现有的全部PE数量。我们从哪里获得的呢?利用vgdisplay命令就行。
这样,一个新的逻辑卷就创建完毕了。剩下的事情就是格式化并挂接它。我们使用如下命令:
# mkfs.ext4 /dev/mapper/NewVolGroup-lv_data
# mkdir /mnt/data
# mount /dev/mapper/NewVolGroup-lv_data/mnt/data
之后就可以使用df命令来确认这个新的磁盘使用情况了。
4.缩放逻辑卷
使用逻辑卷的目的就是冲着它能任意缩放的,所以如何缩放逻辑卷才是关键所在。我们先来看一下如何给逻辑卷增加容量。
我们之前特意留下了/dev/hda4来做这件事。在实际应用中,还需要经历创建分区和物理卷的阶段。将一个新的物理卷加入到一个已有的卷组中使用vgextend命令。在我们的例子中这样操作:
$ vgextend NewVolGroup /dev/hda4
之后我们使用vgdisplay命令就能发现有新的Free PE出现,在我们的测试机中是1274个。这个阶段是扩大了卷组的容量,但是逻辑卷的还没有改变。还需要使用lvresize命令将新增加的PE加入到逻辑卷中。在我们的例子中这样操作:
$ lvresize -l +1274/dev/mapper/NewVolGroup-lv_data
这样再使用vgdisply命令就发现已经没有Free PE了。不过这个时候我们使用df命令查看磁盘空间情况时,并没有发现有什么变化。主要是因为我们还差一个步骤,就是执行resize2fs命令。具体的原因其实很简单,我们新增加的那些磁盘空间还没有格式化呢。这个命令很简单,在我们的例子中只需要这样:
$ resize2fs /dev/mapper/NewVolGroup-lv_data
这样,我们的磁盘容量就增大了,完全是在线的,是不是相当神奇呢?
好了,说完了增加容量,就来看看如何减小容量吧。这次我们要把/dev/hda1抽出来。但是减小容量相对来讲就要麻烦一些了,首先它就是不能在线的了。
我们先要确定/dev/hda1到底有多大,可以通过pvdisplay命令获得。在我们的测试机中得到的结果是5.01G。而我们的硬盘是20G的,那么先要使用resize2fs命令将我们的磁盘调整到20G-5.01G=14990M的大小。我们执行这样的命令:
# umount /mnt/data
# e2fsck -f /dev/mapper/NewVolGroup-lv_data
# resize2fs /dev/mapper/NewVolGroup-lv_data14990M
# mount /dev/mapper/NewVolGroup-lv_data/mnt/data
这之后我们再通过df命令查看就能看出磁盘容量已经缩减了。但是此时我们还有没回收任何PE。这个时候还需要使用lvresize命令来回收PE。回收多少呢?当然是/dev/hda1中含有的那些了。通过pvdisplay命令可以查到有1282个,所以执行命令:
# lvresize -l -1282/dev/mapper/NewVolGroup-lv_data
那现在是不是就可以将/dev/hda1抽出来了呢?还不行。因为通过pvdisplay命令发现,/dev/sda1并没有空闲的PE,而空闲的PE现在在/dev/sda3和/dev/sda4上。/dev/sda4上有1274个Free PE,而/dev/sda3上有8个Free PE(总共1280个PE)。要抽出/dev/sda1,必须是的它的全部PE为Free状态,这个可以借由pvmove命令完成。在我们这个场景中可以使用类似这样的命令:
# psmove /dev/hda1:0-1273 /dev/hda4:0-1273
# psmove /dev/hda1:1274-1281/dev/hda3:1272-1279
这之后再使用pvdisplay查看,就发现/dev/sda1的PE都为Free状态了。这之后就可以使用vgreduce命令,将/dev/sda1抽出了。在我们的场景中可执行类似这样的命令:
# vgreduce NewVolGroup /dev/hda1
需要提醒大家一下,在我们这个例子中,由于/dev/sda1是所有分区中最大的一个,使得无法将它的整个数据移入到任何其他分区中,所以我们在使用psmove命令的时候参数有些复杂。但是这种情况却是在实际应用当中经常遇到的情况。如果遇到了目标分区空余空间比原分区大的时候,PE编号范围就可以省略了。顺便提一句,PE编号是从零开始的。