うちのサーバはCentOSベースで組んでいて、組むときにディスクをRAIDにするのに、低コストにICHxRベース(Intel Matrix Storage Manager)でやろうと思って調べていたが、どうもLinuxのこの手の半ソフトウェアRAIDのサポートはいまいち良くないようであったので、昔からあって世間的に実績も多い、OSのソフトウェアRAIDを採用することにした。
で、しばらく運用していて、昨年アレイを構成しているディスクが1本死んだので、交換を行った。
そもそも、うちでの構成は
% cat /proc/mdstat
Personalities : [raid1]
md1 : active raid1 sdb2[0] sda2[1]
554176 blocks [2/2] [UU]
md0 : active raid1 sdb1[0] sda1[1]
487829632 blocks [2/2] [UU]
こんな感じで、sdaとsdbでミラーを組んでいる。このときは、sdbの方が死んだので、普通にサーバをシャットダウンして電源を落とし、中を開けてsdbの故障したドライブを新しいドライブと交換してから再起動し、
% mdadm --add /dev/md0 /dev/sdb1
% mdadm --add /dev/md1 /dev/sdb2
こんな感じでアレイにパーティションを追加すれば、リビルドしてくれ、完了すれば元通りである。
ところが、今回は、sdaの方が死んだのである。
Sep 6 00:04:45 www kernel: ata1: soft resetting link
Sep 6 00:04:50 www kernel: ata1: link is slow to respond, please be patient (ready=0)
Sep 6 00:04:52 www kernel: ata1.00: configured for UDMA/133
Sep 6 00:04:52 www kernel: sd 0:0:0:0: timing out command, waited 30s
Sep 6 00:04:52 www kernel: ata1: EH complete
Sep 6 00:04:52 www kernel: SCSI device sda: 976773168 512-byte hdwr sectors (500108 MB)
Sep 6 00:04:52 www kernel: sda: Write Protect is off
Sep 6 00:04:52 www kernel: sda: Mode Sense: 00 3a 00 00
Sep 6 00:04:52 www kernel: SCSI device sda: drive cache: write back
Sep 6 00:05:22 www kernel: ata1.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
Sep 6 00:05:22 www kernel: ata1.00: cmd ea/00:00:00:00:00/00:00:00:00:00/a0 tag 0
Sep 6 00:05:22 www kernel: res 40/00:00:00:90:08/40:00:12:00:00/00 Emask 0x4 (timeout)
Sep 6 00:05:22 www kernel: ata1.00: status: { DRDY }
Sep 6 00:05:27 www kernel: ata1: link is slow to respond, please be patient (ready=0)
Sep 6 00:05:32 www kernel: ata1: device not ready (errno=-16), forcing hardreset
Sep 6 00:05:32 www kernel: ata1: soft resetting link
(中略)
Sep 6 00:06:33 www kernel: ata1: SRST failed (errno=-16)
Sep 6 00:06:33 www kernel: ata1: reset failed, giving up
Sep 6 00:06:33 www kernel: ata1.00: disabled
Sep 6 00:06:33 www kernel: sd 0:0:0:0: timing out command, waited 30s
Sep 6 00:06:33 www kernel: ata1: EH complete
Sep 6 00:06:33 www kernel: sd 0:0:0:0: SCSI error: return code = 0x00040000
Sep 6 00:06:33 www kernel: end_request: I/O error, dev sda, sector 975659327
Sep 6 00:06:33 www kernel: raid1: Disk failure on sda1, disabling device.
こんな感じで、そもそもデバイスの応答がない状態になっている。
そもそも、ソフトウェアRAIDは、起動シーケンス中、initrd中のramdisk filesystem中のスクリプトからアクティベートされるので、そこから/にroot filesystemがマウントし直され、/sbin/initが呼び出される以降ではソフトウェアRAIDが機能しているが、それまでの、MBRからGRUBのstage 1が読み込まれ、そこからstage 2 loaderがロードされ、カーネル、initrdのロードと展開といったプロセスの間は、最初の起動ドライブ(つまりはsda)から読み出されるため、sdaが死ぬと起動できなくなるのである。
ここで、ドライブがホットスワップ可能なサーバハードウェアであれば比較的話は早く、障害の起きたドライブを新しいものに交換し、パーティションを設定してmdアレイにパーティションを追加すれば、リビルドできるし、GRUBを再インストールすればブートも可能となり、ダウンタイムゼロで交換作業は完了する。
今回、ホットスワップできない筐体であったので、どうしようかと思ったが、sdaが完全に機能しない状態になっていたとすると、このまま再起動してしまうと二度と起動できなくなってしまうので、サーバの再起動はせず、故障したドライブの電源コネクタを抜き差しすることで電源を再投入し、とりあえずディスクが生きているか確認を行った。
活線挿抜に対応したハードウェアではないので、本来このような作業はリスクを伴うが、今回はやむを得ずこのような対応を執った。
再投入後、
% echo "- - -" > /sys/class/scsi_host/host0/scan
バスの再スキャンを行ってみたところ、sdaではなくsdcでデバイスが認識されてしまった。ギャース。
先にデバイスの削除をしておくべきだったかな。
(以下では、話がわかりにくくなるので、sdcではなくsdaとして話を進めている)
ひとまず中身を確認してみると、とりあえずディスクは読めているようだ。
そこで、sdaのMBRをそのままsdbにコピーした。
% dd if=/dev/sda of=/tmp/mbr bs=512 count=1
% dd if=/tmp/mbr of=/dev/sdb bs=512 count=1
なお、これは下記のように、sdaとsdbのパーティション構成が完全に同じであることが大前提である。違う場合はそのままコピるとパーティションが壊れるので、絶対にやってはいけない。
% fdisk -l /dev/sda
Disk /dev/sda: 500.1 GB, 500107862016 bytes
255 heads, 63 sectors/track, 60801 cylinders
Units = シリンダ数 of 16065 * 512 = 8225280 bytes
デバイス Boot Start End Blocks Id System
/dev/sda1 * 1 60732 487829758+ fd Linux raid 自動検出
/dev/sda2 60733 60801 554242+ fd Linux raid 自動検出
% fdisk -l /dev/sdb
Disk /dev/sdb: 500.1 GB, 500107862016 bytes
255 heads, 63 sectors/track, 60801 cylinders
Units = シリンダ数 of 16065 * 512 = 8225280 bytes
デバイス Boot Start End Blocks Id System
/dev/sdb1 * 1 60732 487829758+ fd Linux raid 自動検出
/dev/sdb2 60733 60801 554242+ fd Linux raid 自動検出
これで、sdbのディスクもMBRも含めてsdaと同じ状態になったので、一旦シャットダウンして、port 1につながっていたsdbのドライブをport 0につなぎかえ、こいつからブートすることにする。
port 1には、新しいドライブをつないでおく。
再起動すると、今までsdbだったドライブがsdaとして見え、普通にブートしてくる。sdbは新しいドライブになっているので、sdbのパーティションをsdaと全く同じになるように切って、mdadmでパーティションをmdアレイに追加してやればOK。
% mdadm --add /dev/md0 /dev/sdb1
% mdadm --add /dev/md1 /dev/sdb2
で、次に何かあった時のために、あらかじめsdaと同じMBRをsdbにコピーしておき、次sdaが死んだ時は、そのままport 0につなぎかえるだけでブートできるようにしておく。
まとめ:
- LinuxでソフトウェアRAID(md)を使っている
- mdパーティションからブートしている
- ホットスワップできない筐体を使っている
上記条件で運用している時は、非常時に備えて
あらかじめsdaのMBRをsdbにコピーしておく。
- sdbが死んだ時は、普通にシャットダウンしてドライブ交換して再起動しmd設定
- sdaが死んだ時は、シャットダウンしてsdbをport 0につなぎなおし、port 1に新しいドライブを入れて再起動しmd設定
ただし、sdaとsdbが同じパーティション構成になっている場合に限る(普通は同じにして使うと思いますが)
最後にお約束ですが、この通りにやって動かなくなっても知りませんので、自己責任でどうぞw