Software RAID
Linux系
LinuxでSoftware RAIDを組んだ時のメモです。
Software RAID について
Linux では簡単に Software RAID を組むことが可能です。
最近は IDE ドライブもかなり安くなってきたので、個人で RAID を組むのもわりと現実的になってきました。
Linux での Software RAID では RAID-0 も RAID-5 も構築できますが、やはり RAID-1(ミラーリング)が一番使われることが多そうだと思うので、以下は RAID-1 を構築してみた時のメモです。
システムのバックアップをしっかりしておけばクラッシュ時の復旧も問題ないですが、RAID-1 でミラーしておけば、HDD が1台壊れても問題なくシステムは稼働するので、システムのダウンタイムを最小限に留めることができます。
結局のところ、クラッシュ時の保険と HDD を2倍用意することとの兼ね合いなんですが、ミラーする余裕がある人は RAID-1 にしてみるのもいいんじゃないでしょうか。
メールサーバや DNS サーバみたいにダウンしていると他に迷惑がかかるようなサーバは出来るだけ RAID-1 にしておいた方がいいと思います。
また、Software RAID と言われるくらいなので、当然 Hardware RAID というものもあります。
これは RAID Controller と呼ばれるチップによってハード的に RAID 構成にしてしまうというものです。
ハードウェア的なので、カーネルがその RAID Controller に対応している必要があります。
対応していない場合には、当然認識しないので使用できません。
また、Hardware RAID の場合は、デバイスの見え方(/dev/mdx とか)や監視方法等がモノによって違うので扱いにくいという側面もあります。
加えて、RAID Controller 自身の故障というファクターも増えます。
私自身は、上記の点から Software RAID の方が良いと現状では思っています。
正直言って Software RAID はけっこう面倒だと思いますが、監視が楽なのと、トラブった時の対応が Hardware RAID の場合は RAID Controller のデバイスドライバが必要だったりするのがかなりイヤなので。
RAID-1 構築手順
以下、RAID-1 を構築する手順を順に並べました。
想定している環境は、現在既に稼働しているシステムが /dev/hda に入っており、それに /dev/hdb を追加し、最終的に /dev/hda, /dev/hdb を RAID-1 にするというものです。
また、本来はカーネル再構築をして RAID 関連のモジュールを全てカーネルに含めるのがベストですが、今回はあえてカーネル再構築しない方法で RAID を構築しています。
大ざっぱな流れは以下のとおりです。
1. 新ディスクに現在のシステムを全てコピー
2. 新ディスクをとりあえず RAID-1 の片側ディスクとして RAID-1 上のシステムを構成
3. 旧ディスクを RAID-1 に追加
OS は turbolinux8 で行いました。
ちなみに、私自身は何度も構築に失敗してます(/o\)
必ずシステムのバックアップを取ってから行いましょう。
新ディスクのパーティションを作成
fdisk で新ディスクのパーティションを作成します。
# fdisk /dev/hdb
ここで作成したパーティションは RAID-1 にした時のパーティションになるので慎重に作成しましょう。
注意は以下の2点です。
・RAID で後から追加するディスク上のパーティションは、既に存在するパーティション以上の容量を持っている必要があります。
従って、新ディスクが旧ディスクよりも容量が大きい場合には、旧ディスクで対応できる容量の範囲でパーティションを切る必要があります。
・パーティションタイプ を0xfdに設定します。
/etc/raidtab 作成
RAID の設定ファイル /etc/raidtab を作成します。
# md0 is the root array raiddev /dev/md0 raid-level 1 nr-raid-disks 2 nr-spare-disks 0 chunk-size 32 persistent-superblock 1 device /dev/hdb1 raid-disk 0 device /dev/hda1 failed-disk 1 # md1 is the swap array raiddev /dev/md1 raid-level 1 nr-raid-disks 2 nr-spare-disks 0 chunk-size 32 persistent-superblock 1 device /dev/hdb2 raid-disk 0 device /dev/hda2 failed-disk 1
設定項目は以下の通り。
設定項目 | 設定内容 |
---|---|
raiddev | 設定する RAID のデバイス名 |
raid-level | RAID のレベルを指定。RAID-1 なら 1 |
nr-raid-disks | RAID を構成するディスク数 |
nr-spare-disks | スペアディスクの数 |
chunk-size | デバイスに書き込むことができる最小のデータ量。RAID-1 の場合は関係ないらしい。が、設定しておかないとエラーになる |
persistent-superblock | RAID デバイスを自動検出してほしい場合に指定。RAID デバイスからブートする場合には自動検出が必須なので必ず指定。これを指定し損ねると RAID デバイス作成からやり直しになるので注意 |
device | RAID デバイスを構成するディスクデバイス名 |
raid-disk | 上記 device の番号 |
failed-disk | 上記 device が無効である時に指定。この指定がある場合には device は RAID に参加しない。各 RAID デバイスの最後が failed-disk 指定になっているところに注意。これが raid-disk 指定だと旧ディスクも RAID 作成時に RAID に参加してしまい、旧ディスクの内容が破壊される |
RAID 作成
以下のコマンドを実行します。
# mkraid /dev/md0 # mkraid /dev/md1
新ディスク上のパーティションに既に Linux のパーティションがあったりすると、上記コマンドはエラーとなります。
この時は -f 付きで mkraid を実行します。
実はこれでもエラーとなるのですが、ここで表示されている通りにすることで mkraid が成功します。
ちなみに、具体的な方法はコメントによると、書いてはいけないらしいので書けません。悪しからず(^_^;
mkraid が成功すると、/proc/mdstat に RAID の情報が出力されるので、ここでちゃんと RAID が作られたかチェックします。
旧ディスクの方は failed-disk 指定なので、当然 2 デバイスのうちの片方しか RAID に参加していません。
ファイルコピー
まず、RAID にした時にルートデバイスとなるパーティション(他にも Linux パーティションを作成するのであれば、その全て)にファイルシステムを作成します。
# mke3fs /dev/md0
その後、作成した RAID ファイルシステム上に全てのファイルをコピーします。
# mount /dev/md0 /mnt # cd / # cp -a (/mnt, /tmp, /proc, /lost+found 等以外) /mnt # cd /mnt # mkdir tmp proc mnt
また、swap も RAID にするのであれば、swap も作成しておきます。
# mkswap /dev/md1
起動ディスク作成
いきなり HDD の MBR を変更して RAID デバイスからのブートにするのは危険すぎるので、まず一度起動ディスクを作成し、そこから RAID デバイスでブートしてみます。(新ディスクの方の MBR だけ変更して、新旧のディスクを入れ替えて /dev/hda からブートしてみるというのはありかも)
ブート時に RAID デバイスを自動検出するために RAID 対応の initrd を作成します。(※カーネル内に RAID 機能を含んでいる場合には必要なし。が、たいていのカーネルはモジュールとして RAID 機能を読み込んでいるので、通常はカーネル再構築しない限り含まれていない)
# mkinitrd --with=raid1 /mnt/boot/initrd_raid 2.4.18-1
もし、SCSI HDD 等ブート時に読み込む必要のあるモジュールがある場合には、合わせて initrd に含めておきます。
次に、RAID 用の lilo の設定をします。
# vi /mnt/etc/lilo.conf # fdformat /dev/fd0H1440 # lilo -r /mnt
上記の fdformat は必須ではないですが念のため。
/mnt/etc/lilo.conf の内容は以下のような感じになります。
disk=/dev/md0 boot=/dev/fd0 map=/boot/map-fd # map ファイルは分けておいた方が安全 install=/boot/boot.b image=/boot/vmlinuz root=/dev/md0 read-only label=LinuxRaid initrd=/boot/initrd_raid
fstab 修正
RAID 上の fstab を RAID 上のファイルシステムを使用するように修正します。
/dev/md0 / ext3 defaults 1 1 /dev/md1 swap swap defaults 0 0
ついでに RAID 上の rc.sysinit の Add raid devices の部分をコメントにしておくといいかも。
別にしなくても問題はないですが、RAID デバイスはブート時に自動検出されるので、rc.sysinit で RAID を有効にする必要はないです。
ここまで作業が終わったら、作成した起動ディスクで起動してみます。
df やら cat /proc/mdstat やら cat /proc/swap やらで RAID が有効になっているかどうかチェックします。
また、その他のシステムも今まで通りの状態であるかを厳密にチェックします。
これ以降のステップに進んでしまうと後戻りは出来ません。
この状態であれば、普通に起動すれば前の状態で起動されるので、慎重にチェックを行ってください。
旧ディスクを RAID に追加
ここまでで新ディスクのみの RAID は構築できているので、いよいよ旧ディスクを RAID に追加します。
旧ディスクを新ディスクと同様に(またはそれぞれのパーティションを多めに)パーティションを作成します。
パーティションタイプを0xfdにするのも同様です。
パーティションを作成したらそれぞれのパーティションを RAID デバイスに追加します。
RAID デバイスに追加するには、/etc/raidtab 内のfailed-disk を raid-disk に修正し、raidhotadd コマンドを実行します。
# fdisk /dev/hda # vi /etc/raidtab # raidhotadd /dev/md0 /dev/hda1 # raidhotadd /dev/md1 /dev/hda2
コマンド実行後は自動的に RAID 間の同期が始まります。
同期の進行具合は cat /proc/mdstat で確認できます。
ブート情報を設定
lilo.conf.hda, lilo.conf.hdb を作成し、それぞれの HDD に対してブート情報を書き込みます。
# vi /etc/lilo.conf.hda # vi /etc/lilo.conf.hdb # lilo -C /etc/lilo.conf.hda # lilo -C /etc/lilo.conf.hdb
hda用のlilo.confは以下のようになります。
hdb 用であれば、boot=/dev/hdbとなります。
disk=/dev/md0 bios=0x80 boot=/dev/hda map=/boot/map install=/boot/boot.b linear image=/boot/vmlinuz root=/dev/md0 read-only label=LinuxRaid initrd=/boot/initrd_raid
あとは、双方からブートできるかをチェックするだけです。
ちなみに、両方とも bios=0x80 指定なので1番目の HDD として起動されることを想定しています。
リンク
さらに詳しい話は以下のJFドキュメントが参考になります。
・The Software-RAID HOWTO
・Boot + Root + Raid + Lilo : Software Raid HOWTO
・LILO "the Linux Loader" の動作について
障害について
RAID上のHDDでハードウェア障害が発生した、もしくはRAID上で何らかの障害が発生してRAIDを構成しているHDDのうち1つがofflineとなったといったようなケースは/proc/mdstatを監視することで発見することができます。
従って、RAIDを構築した後は/proc/mdstatを監視することにより障害検知するような仕掛けをしておくことをおすすめします。
さて、実際にそのような障害が発生した時、つまりRAIDを構成しているHDDのうちの1つがofflineとなった場合について、私が実際経験した2つのパターンを紹介します。
HDD障害
HDDがハードウェア障害となった場合には当然HDDを交換するしかありません。
そのハードウェアにもよりますが、通常は電源をオンにしたままHDDを交換してOSに認識させることはできないので、一度電源を切ってから障害が発生したHDDを新しいものに交換します。
交換後OSを起動してパーティションを以前のディスクと同様に切ります。
その後、raidhotaddを使用してRAIDに追加します。
raidhotadd実行後は自動的にRAIDの再構築が開始されます。
再構築時は非常に負荷が高くなるので、その辺りを考慮してサービスを適宜停止したりした方がよいですが、基本的には通常通りサービスを稼働させながらでもOKです。
RAID不整合
予期せぬ電源断等により、RAIDを構成しているHDD同士でデータが不整合となることがあります。
この場合、起動時に以下のようなRAIDを構築できないというメッセージが表示されます。
md: considering hdc3 ... md: adding hdc3 ... md: adding hda3 ... md: created md2 md: bind<hda3,1> md: bind<hdc3,2> md: running: <hdc3><hda3> md: hdc3's event counter: 00000010 md: hda3's event counter: 00000009 md: superblock update time inconsistency -- using the most recent one md: freshest: hdc3 md2: kicking faulty hda3! md: unbind<hda3,1> md: export_rdev(hda3) md: md2: raid array is not clean -- starting background reconstruction md: RAID level 1 does not need chunksize! Continuing anyway. md2: max total readahead window set to 124k md2: 1 data-disks, max readahead per data-disk: 124k raid1: device hdc3 operational as mirror 1 raid1: md2, not all disks are operational -- trying to recover array raid1: raid set md2 active with 1 out of 2 mirrors md: updating md2 RAID superblock on device md: hdc3 [events: 00000010]<6>(write) hdc3's sb offset: xxxxxxxxxxx md: recovery thread got woken up ... md2: no spare disk to reconstruct array! -- continuing in degraded mode md: recovery thread finished ...
/proc/mdstatを確認すると、片側のHDDがofflineとなっているはずです。
既にメッセージで書かれている通り自動的には復旧できない状態となっており、これもRAIDを再構築するしかないようなので、raidhotaddでofflineとなったディスクを明示的にRAIDへ追加します。
raidhotadd実行後は自動的にRAIDの再構築が開始されます。