Software RAID

最終更新日時:2017-04-28 16:00:14
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-levelRAID のレベルを指定。RAID-1 なら 1
nr-raid-disksRAID を構成するディスク数
nr-spare-disksスペアディスクの数
chunk-sizeデバイスに書き込むことができる最小のデータ量。RAID-1 の場合は関係ないらしい。が、設定しておかないとエラーになる
persistent-superblockRAID デバイスを自動検出してほしい場合に指定。RAID デバイスからブートする場合には自動検出が必須なので必ず指定。これを指定し損ねると RAID デバイス作成からやり直しになるので注意
deviceRAID デバイスを構成するディスクデバイス名
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の再構築が開始されます。

お問い合わせは 掲示板 にて。