ChinaUnix网友:Jerrywjl 作为在几乎所有Linux发行版操作系统中所带的逻辑卷管理方式(LVM),其最大的特点是部署灵活和操作方便。而且在Red Hat Enterprise Linux中LVM也一直被作为默认的磁盘管理方式直接管理系统所在的设备文件。同时LVM能够很好地支持例如软件Raid,裸设备等特殊磁盘类型,以及自带包括线性、条带、镜像、快照等多种功能,甚至在高版本系统中的Lvm2支持RHCS(Red Hat Cluster Suite)中的HA LVM和Cluster LVM,能够实现HA集群中对块设备的资源共享。 写本文的初衷是因为最近不断在网上看到有朋友问及RAID尤其是软件RAID操作部署和管理方面的问题。其实网上这样的文章不在少数,但遗憾的是在个人看来大部分内容千篇一律,所涉及的实际应用和难度也差强人意,而且雷同者或者克隆者甚多。
比较突出的问题是,相信大多数人都知道怎么去做raid,但是怎样维护,出了问题怎么去应用Raid功能的功能实现所谓的容错、备份和优化等,尤其是在一些关键的应用环境上,这方面内容则很少有人提及。
不是本人好出此风头,而是主要本着好人做到底,送佛送到西的原则,希望这篇文章能够对有需要的兄弟姐妹们提供一些帮助,当然各位在感激涕零的同时若能够良心发现考虑喝个茶,吃个包,增进一下感情的话,在下也乐意奉陪之至。
言归正传,这篇文章的目的是通过一个实际的案例来解释软件RAID的一些基本概念和特殊之处,同时关键的关键是在一些企业环境和某些业务上的应用以及维护管理方法。尽管在大多数情况下软件Raid给人的感觉是难登大雅之堂。
首先来说说RAID:
RAID的概念对于所有的administrators来说应该都不陌生了。RAID全称“Redundant Array of Independent Disks”即“独立磁盘冗余阵列”或简称“磁盘阵列”。简单的说RAID 是一种把多块独立的硬盘(物理硬盘)按不同的方式组合起来形成一个硬盘组(逻辑硬盘)从而提供比单个硬盘更高的存储性能和提供数据备份技术。组成磁盘阵列的不同方式称为RAID 级别(RAID Levels)。当然不同的级别对应了不同的功能。其中比较重要的当属冗余或者数据备份,数据备份的功能是在用户数据一旦发生损坏后,利用备份信息可以使损坏数据得以恢复,从而保障了用户数据的安全性。在用户看起来,组成的磁盘组就像是一个硬盘,用户可以对它进行分区,格式化等等。总之,对磁盘阵列的操作与单个硬盘一模一样。
在所有的RAID级别方面恐怕常用的就是Raid-0,1和5。对于这三种Raid级别的具体区别,我不想再花时间去解释,但是一定要注意的是软件Raid还是硬件Raid。因为尽管在级别上的定义是一样的,但是其在实现方式上有着本质的区别,这才是本文要关心的核心问题。
所谓硬件Raid 就是依靠主板和服务器上的Raid控制器(硬件)来实现的Raid功能;硬件Raid效率要比软件Raid更高,但是从操作上面来讲Raid的配置和控制都是在服务器硬件层(BIOS)设置中实现的。
多数的服务器在安装系统之前都必须要建立磁盘阵列,并且系统也只能安装在磁盘阵列上。那么一旦在BIOS完成这方面配置之后,无论是Raid的哪个级别,在操作系统中看到的磁盘都是最终形成的逻辑盘。
同样的,一旦Raid磁盘阵列出现问题,通常情况下修复也只能在硬件层面上进行。事实上这才是我们所说的真Raid,但是硬件Raid一般来讲都需要专门的Raid控制器实现,在价格方面自然是要高出不少。
在这种情况下就产生了一个所谓软件Raid。Raid实际上是依靠操作系统中自带的Raid 配置软件来模拟硬件Raid实现阵列功能的一种做法。相对硬件Raid来说,软件Raid效率显得不太高,但是胜在价格方面有优势,尤其是在当今这种半死不活的经济环境之下尤为吸引。而且软件Raid还有一些其他的特性,比如其管理和控制可以在操作系统的层面上通过命令和工具实现;可以针对磁盘的分区来进行操作(尽管这是一个我现在都想不明白有什么用处的功能)。从性价比来看,所谓穷人的宝马就是这么来的。
综上所述,作为和硬件Raid最大的区别就是软件Raid从操作系统的角度中可以看到所连接的磁盘或者分区的数量,也能够通过Raid工具软件对其进行控制和操作。
不过各位不要高兴太早,因为在软件和硬件Raid之间,还有一种Raid称为Host Raid,为什么说介乎于软硬之间呢?因为Host Raid是一种把初级的RAID功能附加给SCSI或者SATA卡而产生的产品,他是最早由Intel所推行的一套标准。实际上是把软件RAID功能集成到了产品的固件上,从而提高了产品的功能和容错能力。Host RAID目前可以支持RAID 0和RAID 1,而且归根结底还是软Raid。一般现在很多PC机上板载的Raid控制器,多半就是这种。
那么既然软件Raid要通过操作系统来控制和实现,因此有一个突出的问题就是他的数据同步只能同步到大多数情况下操作系统在正常运行中可见磁盘和分区的那个部分。也就是说,以Raid-1为例,如果所有系统分区都安装到Raid-1上,那么软件Raid同步的信息只能是第一分区开始到磁盘结束的那个部分,而在第一分区之前的一些内容,实际上两个磁盘是不同步的。简单地说就是系统安装中识别的第一块盘上会有启动引导记录等内容,而第二块盘上就没有了。这就产生一个麻烦的问题——如果我们将所有系统分区都安装在软Raid-1构建的磁盘阵列上,那么如果第二块盘损坏,系统仍然可以开机而这个磁盘阵列也能降级使用,但是如果恰恰损坏的是第一块盘,由于在第二块盘上没有启动引导信息而导致系统无法启动,自然这个时候再添加镜像什么的也将变得无比麻烦。
因此本文就是设计了这样一个场景,来以图文的方式演示将系统根以及启动分区都安装在软件Raid-1上,对于第一块硬盘损坏之后的解决方法。
对于学习而言,坚持给自己找点麻烦是十分必要的!不过对于这方面比较陌生的朋友来说最好找个虚拟环境进行测试,不要在玩出火的时候拎着一堆血淋淋的硬盘来戳我脊梁。
首先看我们的实验环境,一台RHEL4U7的虚拟机(选择最小安装),使用两块硬盘做Raid-1,所有的系统分区都放在Raid-1上,包括/boot,swap以及/分区。具体情况如下:
软Raid-1其实在分区的时候就已经确定和部署好了:
![]()
在系统安装完成之后的基本情况如下:
[root@localhost ~]# uname -r
2.6.9-78.ELsmp
[root@localhost ~]# fdisk -l
Disk /dev/sda: 4294 MB, 4294967296 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sda1 * 1 13 104391 fd Linux raid autodetect
/dev/sda2 14 78 522112+ fd Linux raid autodetect
/dev/sda3 79 522 3566430 fd Linux raid autodetect
Disk /dev/sdb: 4294 MB, 4294967296 bytes
255 heads, 63 sectors/track, 522 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sdb1 * 1 13 104391 fd Linux raid autodetect
/dev/sdb2 14 78 522112+ fd Linux raid autodetect
/dev/sdb3 79 522 3566430 fd Linux raid autodetect
Disk /dev/md0: 106 MB, 106823680 bytes
2 heads, 4 sectors/track, 26080 cylinders
Units = cylinders of 8 * 512 = 4096 bytes
Disk /dev/md0 doesn't contain a valid partition table
Disk /dev/md2: 3651 MB, 3651928064 bytes
2 heads, 4 sectors/track, 891584 cylinders
Units = cylinders of 8 * 512 = 4096 bytes
Disk /dev/md2 doesn't contain a valid partition table
Disk /dev/md1: 534 MB, 534577152 bytes
2 heads, 4 sectors/track, 130512 cylinders
Units = cylinders of 8 * 512 = 4096 bytes
Disk /dev/md1 doesn't contain a valid partition table
默认挂载情况:
[root@localhost ~]# df -TH
Filesystem Type Size Used Avail Use% Mounted on
/dev/md2 ext3 3.6G 806M 2.7G 24% /
/dev/md0 ext3 104M 13M 86M 13% /boot
none tmpfs 131M 0 131M 0% /dev/shm
以及/etc/fstab中的内容:
[root@localhost ~]# cat /etc/fstab
# This file is edited by fstab-sync - see 'man fstab-sync' for details
/dev/md2 / ext3 defaults 1 1
/dev/md0 /boot ext3 defaults 1 2
none /dev/pts devpts gid=5,mode=620 0 0
none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
/dev/md1 swap swap defaults 0 0
/dev/hdc /media/cdrom auto pamconsole,exec,noauto,managed 0 0
/dev/fd0 /media/floppy auto pamconsole,exec,noauto,managed 0 0
Raid阵列情况:
[root@localhost ~]# cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdb2[1] sda2[0]
522048 blocks [2/2] [UU]
md2 : active raid1 sdb3[1] sda3[0]
3566336 blocks [2/2] [UU]
md0 : active raid1 sdb1[1] sda1[0]
104320 blocks [2/2] [UU]
unused devices: <none>
[root@localhost ~]# mdadm -D /dev/md0
/dev/md0:
Version : 00.90.01
Creation Time : Fri May 1 18:45:44 2009
Raid Level : raid1
Array Size : 104320 (101.89 MiB 106.82 MB)
Device Size : 104320 (101.89 MiB 106.82 MB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 0
Persistence : Superblock is persistent
Update Time : Fri May 1 10:58:08 2009
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
UUID : 03ca737f:77ff488e:5209468d:4ad4c3a7
Events : 0.44
Number Major Minor RaidDevice State
0 8 1 0 active sync /dev/sda1
1 8 17 1 active sync /dev/sdb1
[root@localhost ~]# mdadm -D /dev/md1
/dev/md1:
Version : 00.90.01
Creation Time : Fri May 1 18:45:42 2009
Raid Level : raid1
Array Size : 522048 (509.90 MiB 534.58 MB)
Device Size : 522048 (509.90 MiB 534.58 MB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 1
Persistence : Superblock is persistent
Update Time : Fri May 1 10:54:49 2009
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
UUID : 3444ec65:0a7fb6fd:d984f9e9:73c8ae0b
Events : 0.4
Number Major Minor RaidDevice State
0 8 2 0 active sync /dev/sda2
1 8 18 1 active sync /dev/sdb2
[root@localhost ~]# mdadm -D /dev/md2
/dev/md2:
Version : 00.90.01
Creation Time : Fri May 1 18:45:43 2009
Raid Level : raid1
Array Size : 3566336 (3.40 GiB 3.65 GB)
Device Size : 3566336 (3.40 GiB 3.65 GB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 2
Persistence : Superblock is persistent
Update Time : Fri May 1 11:07:28 2009
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
UUID : 9ea6a91b:43701808:c6a3f0ae:ed0e95cc
Events : 0.226
Number Major Minor RaidDevice State
0 8 3 0 active sync /dev/sda3
1 8 19 1 active sync /dev/sdb3
[root@localhost ~]# cat /etc/mdadm.conf
# mdadm.conf written out by anaconda
DEVICE partitions
MAILADDR root
ARRAY /dev/md2 level=raid1 num-devices=2 UUID=9ea6a91b:43701808:c6a3f0ae:ed0e95cc
ARRAY /dev/md1 level=raid1 num-devices=2 UUID=3444ec65:0a7fb6fd:d984f9e9:73c8ae0b
ARRAY /dev/md0 level=raid1 num-devices=2 UUID=03ca737f:77ff488e:5209468d:4ad4c3a7
现在开始动手破坏这个阵列,方法很简单,关机之后将第一块硬盘抽走就是了。我用的是虚拟机,所以这也就是动动手指头的事。
在开机之后的现象将是一片黑屏且没有任何信息,这显然说明软件Raid-1上无法对启动分区之前的内容进行全面的同步,至少开机连自检以及GRUB相关信息都没有,这样我们的破坏欲又一次得到了满足!
那么之后我们将有两种选择:
- 将原有的磁盘阵列降级为普通磁盘,至少将系统成功启动起来之后再去备份数据;
- 找一块新的盘替换拔走的盘这样来恢复原来的磁盘阵列以及其功能。
我们首先考虑第一种方法,即将原来的整个阵列降级为单个硬盘来启动系统。
在当前的状况下只能进入rescue模式了:
![]()
在rescue模式询问自动挂载根的时候我选择的是continue,但是挂载是不成功的:
![]()
![]()
不要理会提示,进入系统之后,我们可以看到当前的分区状况,这个时候有一个关键步骤是将我的根所在分区挂载到/mnt/sysimage目录下,当然/mnt/sysimage要自己手工建立,因为一旦操作成功,我们将获得一个grub的操作环境(注意为了操作和恢复方便,我将swap文件系统暂时禁用了):
![]()
完成之后,即可运行grub命令来进入grub shell,这样就可以手动将GRUB信息写入到MBR中去,我想如何在grub shell中安装GRUB应该不用我多说了,我以前有一篇关于系统启动trouble shooting的帖子曾经详细阐述过这个问题。操作完成之后quit,退出grub的shell。下面是截图:
![]()
事实上在完成这一个操作之后,系统可以直接重启,但这个时候系统是以一个降级RAID身份来运行的。
如图:
![]()
这无疑将是一种简单高效和快捷的方法,尤其在阵列出现问题而导致系统无法启动的情况下,通过这样的操作能够给我们极大的信心!后续的操作其实不需要我多说了,可以直接将一个新盘插入到原来的槽位上,然后选择mdadm /dev/md0 –a命令向阵列中同步新盘。
但是如果将系统完全从一个阵列转换为单盘的话,显然事情还没有这么简单,因为即便开机grub加载成功,但是进入系统之后也因为原先的/etc/fstab内容不正确而导致问题,所以需要手动将/etc/fstab改正如下:
![]()
同时要改的还有启动分区的grub.conf,那么我们可以临时创建一个空目录,将/dev/sda1挂上:
![]()
别以为就此万事大吉了,因为如果只改完这些之后就开机重启,系统会因为磁盘类型还是software raid而导致启动的时候加载raid模块出错并产生kernel panic。所以最后的工作是fdisk将分区类型针对现有的情况分别改成83和82,也就是标准linux磁盘分区以及swap分区:
![]()
同时将/etc/fstab中的mdadm.conf信息全部注释:
![]()
因为改动分区类型不会影响文件系统以及其上的数据信息,所以这两步操作可以放心执行。完成之后重新启动系统则一切正常:
![]()
现在我们来看看第二种方法,即在抽走第一块硬盘之后添加一块新的硬盘来重组阵列并重启系统。应该来说,这才是一种彻底解决问题的方法。
不过在虚拟机里做这样的操作最大的问题是,当抽走原来的sda之后在原来的槽位上插入新盘,这块新盘将变为sda,而原有的第二块硬盘会变成/dev/sdb。但在虚拟机上,我没法像刚才那样在/dev/sdb上安装盒建立grub并指定系统去以/dev/sdb启动,所以我这里采取一个简单的策略,即将/dev/sdb上的第一个分区即启动分区以及整个盘头都dd到新的硬盘上,这样我至少能够确保系统能够启动起来。
当然在真实的环境中自然不用这样麻烦。因为完全可能在BIOS中指定以那块硬盘作为启动盘。
下面开始操作,针对新添加的硬盘,还是先进入rescue模式,按照原来的/dev/sdb的结构进行分区。这里的分区需要严格按照柱面来划分确保和原来的/dev/sdb一模一样。
![]()
这是完成之后的分区情况,将分区信息写入到分区表:
![]()
现在将/dev/sdb1和/dev/sdb的盘头都dd到/dev/sda:
![]()
因为盘头信息只需要第一个块,包含了MBR以及分区表,所以512字节足够。在dd完成之后像刚才那样将有文件系统的/dev/sdb3挂载到/mnt/sysimage目录下,这样既可获得grub shell进行后续的操作:
当然,为了确保万无一失,我恐怕需要针对现在的/dev/sdb和/dev/sda的盘头都要手动重写GRUB到MBR中,这样在/dev/sdb中有启动系统的全部信息,而在/dev/sda中有盘头到启动分区的全部内容,这些信息对我们启动系统来说应该是足够了!
同时既然这次是有新的盘添加到原来的阵列中来进行mirror,所以自然我不用再更改/etc/fstab以及grub.conf文件,同时也不用改分区标志和/etc/mdadm.conf文件:
![]()
![]()
![]()
完成之后quit退出grub shell,之后exit重启系统,再次见到了我们熟悉的GRUB启动界面:
![]()
在系统启动过程中会有一个fsck的过程,但是由于我们事前没有进行过任何的阵列同步,所以现在整个的阵列是在降级使用中:
![]()
通过cat /proc/mdstat或者mdadm –D都可以看到:
所以下面的工作就是分别手动同步这三个阵列:/dev/md0,/dev/md1和/dev/md2
![]()
![]()
在整个同步中,世间最漫长的是/dev/md2,因为这是/分区,可以通过watch –n1 “cat /proc/mdstat”查看到同步的状态和进程:
![]()
同步完成之后,整个阵列恢复也就成功了。若再重启系统,则没有任何手工干预的过程。实验到此成功!
总结:
通过上面的实验,我们完整地演示了一次软件Raid维护和修复的过程。可能在大多数情况下这套过程很多人都比较熟练。但是对于在系统根分区上部署软Raid的做法,恐怕使用的人就不怎么多了。
不过从上面的过程看,操作方法是一样的,只不过要涉及更多的系统启动原理,救援模式使用以及文件系统方面的内容。连同上期所发表的LVM缩根的文章,希望各位在铤而走险之前一定要先了解并且是比较透彻了解这些预备知识。毕竟实践出真知,但也尽量少走弯路 |