软Raid升级—单盘分身大法 ChinaUnix网友:Jerrywjl 大凡长期混迹于生产环境风口浪尖的哥们,只要一看到Raid前面的“软”字估计立马会嗤之以鼻。和硬件Raid最大的不同,是各种类型的软件Raid,甭管是Host Raid,Dm Raid,板载Raid卡等等,说一千道一万都是要依赖于操作系统实现和控制的东西。既然如此,性能和兼容性的问题就成了软Raid饱受诟病的先天不足。 的确,在大多数号称关键、要命、企业级和最重要是财大气粗的生产业务环境上,软Raid这种东西就如上不得席面的狗肉一样难登大雅之堂(尽管狗肉在当今的确是个好东西……省略感慨和口水数千)。不过话说回来,甭管怎样,这世道还是穷人居多,钱少日子得照过,容灾也一样要考虑,所谓穷价值万贯嘛!因此对于在生产环境中一样要考虑冗余和天灾人祸的小企业和广大善良的第三世界来说,软件Raid这种东西自然不乏生存的空间和大把证明自己是个玩意的环境。就像你如果吃不起人参,但至少大可以对着一盘萝卜豪放一把。 至于本人,其实本来并不愿意陷入这种纷争和阶级对立当中。但是无奈受人钱财替人消灾,只要是大爷们花了银子,系统上甭管软的硬的有问题和需求都得分析都得看。最后把客人伺候爽了,银子还不是直接落自己口袋!唉!这里我突然想到一个有点不雅的比喻,相信不少老少爷们都已经心照不宣了。呵呵,没办法,世道就这样。借用当今流行的术语,恐怕不少人都是活在这种潜规则中…… 刚才说到哪了?Raid,嗯,其实倒霉就在这。提到这个东西个人感觉比较恶心的是:第一,使用软Raid的问题居然在所谓的生产环境中层出不穷!这倒是可以理解——毕竟这也是咱天朝和谐社会的主要阶级构成;第二,越来越多的大爷们在潜意识中赋予了软Raid无限的小宇宙,大有认为软Raid这种东西在生产环境和数据容灾上无往不利,人挡杀人佛挡杀佛之势。这样在无比险恶的生产环境中,对软Raid这种玩意的折腾上就多了很多让人无限遐想的玩法。这次要写的血泪史就来源于某位大爷的灵光一现。但也着实让俺长了回见识: 场景很简单,某兄弟有一个生产系统,不过照我估计也就是跑在PC机上的生产系统。因为他告诉俺这个生产系统只有一块硬盘,是典型的系统数据和用户数据一勺烩的玩法。 而需求更简单:考虑到来自像七五、十三层、七十码等各种和谐社会的惊喜,准备弄块同样的硬盘,在不重装原来系统和破坏数据的情况下把这个系统从单盘升级到软件Raid 1。做硬Raid没预算,而且也不太好折腾,开不了奔驰夏利总是可以飚一把的吧!? 怎么样?环境和要求够简单的吧?!不过各位听好了,原来的磁盘连个Raid毛都沾不上,但现在要从那块毛都没有的单盘彻底脱胎换骨到两块盘的软Raid 1,而且还必须要保证原来的系统和数据无损,唯一的条件是可以停机操作(呵呵,和没说一样!不停机你来试试!?)所以,应该说这种要求要真弄起来还是有点难度的!没办法,只能抱着试试看的态度,在试验环境中折腾了数把,最终折腾出来的结果也真让俺长了见识!下面就将俺操作的过程全部show出来,喜欢玩心跳和找刺激或者晚上总失眠哥们只管找个生产环境照葫芦画瓢验证一把!但丑话先说好,若出了任何问题怨不着俺,要怪就去咱怪天朝社会为什么不提供一个让自己用得起硬Raid的环境吧! 我的测试环境如下:一台最小化安装的RHEL4U7 32bit虚拟机,4G硬盘。其中/boot 100MB,swap 512MB,/是2048MB。准备另加一块4GB的硬盘和原来的硬盘组成软件Raid。这就是试验的全部家当,所谓人穷志短,没办法! 首先第一步,将原来硬盘所有的分区类型改成软件raid,并且确保新添加的分区方式完全一摸一样。下面是经过处理的分区表,不知道怎样将分区类型改成软件Raid的哥们就请当我什么都没说,但请务必就此回头是岸! [root@dhcp-0-118 ~]# fdisk -l /dev/sda 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 274 2096482+ fd Linux raid autodetect /dev/sda3 275 339 522112+ fd Linux raid autodetect 接着对于俺这种懒人就用懒办法将/dev/sda上的分区表来个移形幻影: [root@dhcp-0-118 ~]# sfdisk -d /dev/sda | sfdisk /dev/sdb Checking that no-one is using this disk right now ... OK Disk /dev/sdb: 522 cylinders, 255 heads, 63 sectors/track sfdisk: ERROR: sector 0 does not have an msdos signature /dev/sdb: unrecognized partition Old situation: No partitions found New situation: Units = sectors of 512 bytes, counting from 0 Device Boot Start End #sectors Id System /dev/sdb1 * 63 208844 208782 fd Linux raid autodetect /dev/sdb2 208845 4401809 4192965 fd Linux raid autodetect /dev/sdb3 4401810 5446034 1044225 fd Linux raid autodetect /dev/sdb4 0 - 0 0 Empty Successfully wrote the new partition table Re-reading the partition table ... If you created or changed a DOS partition, /dev/foo7, say, then use dd(1) to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1 (See fdisk( .) 现在两块盘上的分区应该是完全一样了! 下面在原有的三个分区中先对启动分区,即/boot进行操作。 首先卸载: [root@dhcp-0-118 ~]# umount /boot/ 然后来一招霸王硬上弓(这里又带来遐想无限……),对/dev/sda1强行做一个单盘的Raid: [root@dhcp-0-118 ~]# mdadm -C /dev/md0 -l1 --force -n1 /dev/sda1 mdadm: /dev/sda1 appears to contain an ext2fs file system size=104388K mtime=Fri Jul 24 14:53:25 2009 Continue creating array? y mdadm: array /dev/md0 started. 之后将第二块盘的第一个分区加进去升级,让/dev/md0变成名正言顺的Raid1: [root@dhcp-0-118 ~]# mdadm /dev/md0 -a /dev/sdb1 mdadm: hot added /dev/sdb1 [root@dhcp-0-118 ~]# mdadm -G /dev/md0 -n2 [root@dhcp-0-118 ~]# cat /proc/mdstat Personalities : [raid1] md0 : active raid1 sdb1[1] sda1[0] 104320 blocks [2/2] [UU] unused devices: <none> 一般来说这步操作应该不会有什么问题,若有问题就请好好反省自己的人品! 确认一下: [root@dhcp-0-118 ~]# df -TH Filesystem Type Size Used Avail Use% Mounted on /dev/sda2 ext3 2.2G 802M 1.3G 40% / none tmpfs 131M 0 131M 0% /dev/shm /dev/md0 ext3 104M 13M 86M 13% /boot 下面需要重新建立initrd.img文件,更新存储这个静态内核模块的镜像文件系统: [root@dhcp-0-118 boot]# mkinitrd -f initrd-2.6.9-78.ELsmp.img $(uname -r) 这个操作也一定要完成,否则到待会重启动系统的时候自然会让你叫苦不迭。 现在修改/etc/fstab和/boot/grub.conf,既然现在是Raid了嘛,当然不能再和单盘同日而语了: 下面是原来的文件内容: [root@dhcp-0-118 ~]# cat /boot/grub/grub.conf # grub.conf generated by anaconda # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/sda2 # initrd /initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Red Hat Enterprise Linux AS (2.6.9-78.ELsmp) root (hd0,0) kernel /vmlinuz-2.6.9-78.ELsmp ro root=LABEL=/ initrd /initrd-2.6.9-78.ELsmp.img title Red Hat Enterprise Linux AS-up (2.6.9-78.EL) root (hd0,0) kernel /vmlinuz-2.6.9-78.EL ro root=LABEL=/ initrd /initrd-2.6.9-78.EL.img [root@dhcp-0-118 ~]# cat /etc/fstab # This file is edited by fstab-sync - see 'man fstab-sync' for details LABEL=/ / ext3 defaults 1 1 LABEL=/boot /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 LABEL=SWAP-sda3 swap swap defaults 0 0 /dev/hdc /media/cdrecorder auto pamconsole,exec,noauto,managed 0 0 /dev/fd0 /media/floppy auto pamconsole,exec,noauto,managed 0 0 这是修改之后的文件内容: [root@dhcp-0-118 ~]# cat /boot/grub/grub.conf # grub.conf generated by anaconda # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/sda2 # initrd /initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Red Hat Enterprise Linux AS (2.6.9-78.ELsmp) root (hd0,0) kernel /vmlinuz-2.6.9-78.ELsmp ro root=/dev/md1 initrd /initrd-2.6.9-78.ELsmp.img title Red Hat Enterprise Linux AS-up (2.6.9-78.EL) root (hd0,0) kernel /vmlinuz-2.6.9-78.EL ro root=/dev/md1 initrd /initrd-2.6.9-78.EL.img [root@dhcp-0-118 ~]# cat /etc/fstab # This file is edited by fstab-sync - see 'man fstab-sync' for details /dev/md1 / 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 # LABEL=SWAP-sda3 swap swap defaults 0 0 /dev/hdc /media/cdrecorder auto pamconsole,exec,noauto,managed 0 0 /dev/fd0 /media/floppy auto pamconsole,exec,noauto,managed 0 0 红色的是俺修改过的。 完成之后,重启系统用光盘引导进入rescue模式。针对/dev/sda2和/dev/sda3分别建立单个磁盘的软Raid。在Rescue模式的进入过程中选择skip。 剩下的全部手动操作: # mdadm -C /dev/md1 -l1 --force -n2 /dev/sda2 # mdadm -C /dev/md2 -l1 --force -n2 /dev/sda3 # mdadm /dev/md1 -a /dev/sdb2 # mdadm /dev/md2 -a /dev/sdb3 # mdadm -G /dev/md1 -n2 # mdadm -G /dev/md2 -n2 上面的两条命令相信各位看官理解上应该不是什么问题。如果还有很多问题的哥们,恭喜你已经走上了这条不归路,俺只能建议你继续务必理解明白,并及时烧香拜佛祈求佛祖。这里唯一要注意的是,这个时候对于大的文件系统或分区而言,-G是绝对一个漫漫长路,正好有机会思考人生。但不管你产生什么样的冲动,都请务必要通过不断查看cat /proc/mdstat来确保所有的数据同步都完成再执行下一步操作。否则的话,我将豁出身家性命赌你死得要多难看有多难看!当然在这个时候很多哥们会开始感悟自己要有个UPS,那该多好啊...... 在漫长的同步过程彻底完成之后,建议你扫扫机器上的蜘蛛网,并将已经成为Raid 1的阵列mount起来看看其中的内容是否OK。如果的确已经OK,那么恭喜你!你的铤而走险已经成功了一半了。这个50%非常关键,因为他预示着你的Raid 1阵列已经建立起来。现在则可以重启系统。 不过这个时候纠结的事情来了。通过本人的测试结果发现,其实这个时候你的系统是无法启动起来的。因为在这个时候尽管系统能够正常走过GRUB,内核模块加载甚至是init,但在进入到/etc/fstab阶段会在挂载根文件系统的时候报告一个很怪异的错误而导致整个系统进入到repaire模式。在这里特意给大家留下一个截图让各位充分享受一下这种刺激!从报错的信息可以看到,文件系统中的superblock报告该文件系统的大小是524120个block,而块设备大小是524096个block。文件系统将块设备塞爆了!?这让俺不禁联想到了伟大天朝尤其是首都的房地产政策和广大第三世界的刚性需求。不过各位大可放心,EXT3文件系统就算烂透了也比那强百倍,因为至少还能够按需分配,所以我们当然还可以有足够的回旋余地。 不过回到技术方面,其实对于该问题的原因,我只能大概推测,由于软件Raid的元数据是要占用一部分的块设备空间,尽管这个占用的空间不大可能也就几十个到几百个块,但这个世界就是充满着不确定性。确定的就像这幅截图所显示的,块设备和文件系统的大小的确还没有聪明到能够自动谈妥条件,因此系统启动就因为这种不一致停在这里过不去了。看来还是得等俺帮他一把。 对于这个问题的解决方法,很多哥们想到了fsck。呵呵!其实不瞒各位,本人一开始也想到了。但之所以在这个地方纠结是因为即便你fsck表面上修复了文件系统,下次重启还是这样。所以修了也是白修。对于这个问题的解决。我们还是要以刚才的方式进入到rescue模式中。想必各位已经猜到了,下面就要对文件系统动粗了——请出resize2fs缩骨大法! 先在rescue模式下对文件系统先进行一次强制修复: # e2fsck -f /dev/sda2 # e2fsck -f /dev/sdb2 然后根据上面报错的提示正式施展传说中的锁骨大法: # resize2fs /dev/sda2 524096 # resize2fs /dev/sdb2 524096 老衲不忘啰嗦一句,这里的resize2fs的单位是KB而不是block,因为事前俺曾经用dumpe2fs查看并确认过文件系统块大小是block size=1KB,所以块数量和KB数量是一致的。毕竟这个文件系统也就是2GB左右。而在很多真实环境中的块大小可能是4KB或者是其他值,那么一定要将块数量换算为KB!所以建议数学不好的哥们就不要铤而走险了,当然如果愿意请再下吃顿饭交流一下感情的话,俺倒是可以豁出去帮你算一下!如果是MM的话那俺可能破戒上杆子帮忙算一下。但最后还是那句话:风险自负!善哉善哉! 现在再次重启系统,然后你就会看到......哇哈哈哈!还是卡在了fstab这里!但报错已经不一样了,因为这次是针对/dev/sda1所在的文件系统,而至于那个命根子根分区,自然已经通过了检查。当然错误类型也还是和刚才一样。但是由于根分区现在已经挂上,且系统启动到这里,/boot文件系统已经完成了他光荣的使命,所以我们就不用再去rescue模式中纠结了! 直接输入管理员密码进入repair模式,运行命令: # e2fsck -f /dev/sda1 # e2fsck -f /dev/sdb1 并根据刚才的出错提示故伎重演: # resize2fs /dev/sda1 104320 # resize2fs /dev/sdb1 104320 顺便把/etc/fstab中被禁用掉的swap给改回来: # mount -o remount,rw /dev/md1 / # vi /etc/fstab 将原来注释的swap那行改为: /dev/md2 swap swap defaults 0 0 保存退出并重建swap: # mkswap /dev/md2 最后别忘了将grub在/dev/sdb上重写一下。为什么要重写grub?这实际上就是软件Raid一个天大的陷阱!因为作为操作系统管理的这种软Raid实际上是无法百分百完成设备镜像的。而没有完成同步的部分就在盘头,还恰好就是系统启动的关键,即MBR和后续的一部分空间。呵呵,这个世界就是这么奇妙,硬Raid虽然贵,但胜在兼容性好并且性能也没人说三道四;软Raid尽管经济和高可控性,但类似于这样的命门也足够你恶心一阵子了。所以言归正传,如果没有这部分空间的同步,假如你的第二块盘挂了,那么单靠第一块盘系统自然什么事都没有,这会让很多管理员麻痹大意。不过如果你不好命正好是第一块盘中招,那系统会连GRUB都进不去!这种恐怖的场景足以让很多菜鸟管理员一身冷汗了。所以既然如此,就将一切可能发生的情况预料在前。 完成这步操作之后,终于可以放心重启整个系统。重启过程正常情况下不会有任何问题,完成之后显示阵列信息,一切OK!这次的分身大法终于彻底完成! [root@dhcp-0-118 ~]# cat /proc/mdstat Personalities : [raid1] md1 : active raid1 sdb2[1] sda2[0] 2096384 blocks [2/2] [UU] md2 : active raid1 sdb3[1] sda3[0] 522048 blocks [2/2] [UU] md0 : active raid1 sdb1[1] sda1[0] 104320 blocks [2/2] [UU] unused devices: <none> [root@dhcp-0-118 ~]# df -TH Filesystem Type Size Used Avail Use% Mounted on /dev/md1 ext3 2.2G 805M 1.3G 41% / /dev/md0 ext3 104M 13M 87M 13% /boot none tmpfs 131M 0 131M 0% /dev/shm [root@dhcp-0-118 ~]# mdadm -D --scan > /etc/mdadm.conf [root@dhcp-0-118 ~]# cat /etc/mdadm.conf ARRAY /dev/md1 level=raid1 num-devices=2 UUID=f4e187fb:8a2ae9f5:689c862d:197ed8e5 ARRAY /dev/md2 level=raid1 num-devices=2 UUID=684e1a26:a570b86e:ffc29636:3d25bf08 ARRAY /dev/md0 level=raid1 num-devices=2 UUID=6a743391:49212382:fd830cd8:316b7ba5 纵观整个操作的过程可以发现,尽管需求很简单,但是在实际操作过程中会出现各种类型的意外,对于意外的观察和处理,务必要做到胆大心细。而且如果哪位哥们真敢在你的生产系统上赴汤蹈火的话,还需要比我考虑更多的因素,如Raid同步的数据量,停机时间,原有磁盘是否还有LVM,是否在整个环境中有UPS这样的护身符等等。反正说一千道一万,我还是那句话:真的希望各位在做方案或者部署的时候凡事想在前头,我这么折腾也是被人逼出来。否则这种顾头不顾腚的事情还是建议各位少干。
[ 本帖最后由 八重樱 于 2009-9-17 07:43 编辑 ] |