概要
RAID5 を構成するディスク4台の内、1台が物理故障でアクセス不可となった結果、 RAID 内のデータに全くアクセスできなくなってしまった時のデータサルベージのメモです。通常、 RAID5 であればディスク1台の故障に耐えられるはずですが、1台の故障で何故か RAID が崩壊してしまいました。
似たような状況に陥った人の参考にしてもらったり、後学のために有識者の方からマサカリを投げてもらえればと思い記事にしておきます。
ちなみにこの記事を参考にして発生したいかなる損害も私は責任を負いません。全て自己責任にて実施してください。より確実にデータを復旧したい場合はおとなしくデータ復旧サービスに依頼しましょう。
環境
- 自宅鯖 (NAS)
- HDD: WD Red 10TB x 4
- HDD エンクロージャー: TS431U
- OpenMediaVault 5.6
- ソフトウェア RAID (md-raid) による RAID5
- RAID 内のファイルシステム: ext4
起きた事
初動
外出先で自宅鯖のサービスが稼働していないことに気づく。スマホから SSH で接続してみると RAID が I/O Error で停止していることが判明。その時の /proc/mdstat
は次の通り。
# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : active raid5 sdb[4](S) sdd[3](S) sda[0](S)
29298917376 blocks super 1.2 level 5, 512k chunk, algorithm 2 [4/0] [____]
bitmap: 11/73 pages [44KB], 65536KB chunk
unused devices: <none>
・・・なんかおかしいぞ・・・?
RAID のマウントポイントを確認してみるも、当たり前のように I/O Error となる。
自宅鯖のサービスはこの RAID の上にデータを保持しているため、 RAID の不調によってサービスも停止していると判断。以前のバージョンの OpenMediaVault を利用していた際に、 HDD エンクロージャーが急に切断される事象が多発した経験があり、それが再発した可能性を考える。ただ sdc
が消えている点と残りの sda
, sdb
, sdd
が全て (S)
になっている点は気がかり・・・
スマホからではオペレーションしづらいので、 cat /proc/mdstat
の結果だけをファイルに保存して systemctl reboot
を実行。これで RAID が無事復旧することをお祈り・・・したんだけれども、一向に SSH がつながらない・・・
SSH がつながらず、外出先からは何もできなくなってしまったので、何も見なかったことにした。
■ この時点の振り返り
-
cat /proc/mdstat
の結果を記録しておいたのは後から非常に役に立った。
ほぼデフォルトのパラメータではあったが、復旧の際に確信をもってトライすることができた。 -
mdadm --detail /dev/md0
を実行し、その結果を記録しておくべきだった。
致命的ではなかったが/proc/mdstat
に出力されない情報をロストしてしまった。 -
mdadm --examine /dev/sda
等を実行し、その結果を記録しておくべきだった。
この後、この時点では正常な HDD へのアクセスも I/O Error でできなくなっていたという思い込みで復旧を続けたが、今考えれば根拠が薄かったと思う。
状況確認(レスキューモード)
帰宅後に自宅鯖を見てみると、レスキューモードで起動していた。確認してみると RAID がスタートできておらず、 /etc/fstab
に記載された RAID のデバイスをマウントできていないようだった。
この時の /proc/mdstat
は次の通り。
# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md0 : inactive sdd[3](S) sda[0](S) sdb[4](S)
29298917376 blocks super 1.2
unused devices: <none>
なんか表示がシンプルになってしまっている・・・
mdadm --detail /dev/md0
は次の通り。
# mdadm --detail /dev/md0
/dev/md0:
Version : 1.2
Raid Level : raid0
Total Devices : 3
Persistence : Superblock is persistent
State : inactive
Working Devices : 3
Name : openmediavault:volume1 (local to host openmediavault)
UUID : 9e3ad5fb:c8e80c01:67ace5ae:2c2dcbf3
Events : 7238835
Number Major Minor RaidDevice
- 8 0 - /dev/sda
- 8 48 - /dev/sdd
- 8 16 - /dev/sdb
ちょっとまって Raid Level : raid0
とか言ってるんですが?あなた RAID5 のはずですよね?
mdadm --examine /dev/sda
は次の通り。
# mdadm --examine /dev/sda
/dev/sda:
Magic : a92b4efc
Version : 1.2
Feature Map : 0x9
Array UUID : 9e3ad5fb:c8e80c01:67ace5ae:2c2dcbf3
Name : openmediavault:volume1 (local to host openmediavault)
Creation Time : Sun Sep 3 20:56:35 2017
Raid Level : raid5
Raid Devices : 4
Avail Dev Size : 19532611584 (9313.88 GiB 10000.70 GB)
Array Size : 29298917376 (27941.63 GiB 30002.09 GB)
Data Offset : 262144 sectors
Super Offset : 8 sectors
Unused Space : before=262056 sectors, after=0 sectors
State : clean
Device UUID : 89015277:ddf9ad4d:14e7af9e:ae8f37af
Internal Bitmap : 8 sectors from superblock
Update Time : Fri Nov 24 13:23:54 2023
Bad Block Log : 512 entries available at offset 72 sectors - bad blocks present.
Checksum : 647fa998 - correct
Events : 7238835
Layout : left-symmetric
Chunk Size : 512K
Device Role : spare
Array State : .... ('A' == active, '.' == missing, 'R' == replacing)
よかったこっちは Raid Level : raid5
になっている。ところで Device Role : spare
ってなんで? Array State : ....
ってヤバくない?あと bad blocks present.
が良い味出してる。 /dev/sdb
, /dev/sdd
も似たような感じだった。流石に bad blocks present.
はなかったけど。
smartctl -a /dev/sda
は次の通り。
# smartctl -a /dev/sda
(中略)
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE
1 Raw_Read_Error_Rate 0x000b 100 100 016 Pre-fail Always - 0
2 Throughput_Performance 0x0004 130 130 054 Old_age Offline - 108
3 Spin_Up_Time 0x0007 165 165 024 Pre-fail Always - 409 (Average 389)
4 Start_Stop_Count 0x0012 100 100 000 Old_age Always - 181
5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0
7 Seek_Error_Rate 0x000a 100 100 067 Old_age Always - 0
8 Seek_Time_Performance 0x0004 128 128 020 Old_age Offline - 18
9 Power_On_Hours 0x0012 093 093 000 Old_age Always - 54596
10 Spin_Retry_Count 0x0012 100 100 060 Old_age Always - 0
12 Power_Cycle_Count 0x0032 100 100 000 Old_age Always - 44
22 Helium_Level 0x0023 100 100 025 Pre-fail Always - 100
192 Power-Off_Retract_Count 0x0032 094 094 000 Old_age Always - 7897
193 Load_Cycle_Count 0x0012 094 094 000 Old_age Always - 7897
194 Temperature_Celsius 0x0002 240 240 000 Old_age Always - 27 (Min/Max 20/65)
196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0
197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0
198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 0
199 UDMA_CRC_Error_Count 0x000a 200 200 000 Old_age Always - 0
(後略)
稼働時間が54,596時間ってすごいな・・・6年以上動きっぱなし。いつ壊れても不思議ではない。他は過去に温度が65度まで到達したことがあるのと、 Spin_Up_Time
が Average より遅くなっているのが気になるくらいかなぁ。
状況確認(障害 HDD)
自宅鯖をパワーオフして、 RAID 上に表示されなくなった /dev/sdc
のディスクを別のマシンにつなぎなおす。
・・・うん、カッコンカッコン言って一向にアクセスできない。完全に物理故障だわコレ。めでたく3万円台(新品価格)の文鎮が完成しました。やったね!
この HDD は /dev/sda
の HDD と同じタイミングで買ったものだから、6年以上稼働したようだ。天寿は全うしたと言ってもいいだろう。
そして、故障した /dev/sdc
を接続しないまま自宅鯖の電源を入れなおしたところ、それまで /dev/sdd
と認識されていた HDD が /dev/sdc
と認識されるようになり、この後のデータ復旧のペースを落とすのであった・・・
状況整理
ここまで確認した内容から状況を整理してみる。
- 自宅鯖が稼働している中、物理的に HDD が1つ故障した。
- 故障したことにより、この HDD へのアクセスが刺さったままになった?
- この故障に引っ張られて、正常な HDD へのアクセスもできなくなった?
- HDD エンクロージャー (TS431U) で利用されているコントローラは、
lsusb
で確認すると JMS567 だった。 - もしかしたら HDD の故障に伴い、コントローラがすべての HDD の応答を返せない状況になってしまったのかもしれない。
- HDD エンクロージャー (TS431U) で利用されているコントローラは、
- そんなこんなで自宅鯖の RAID5 は崩壊したようだ。
- 正常な HDD も I/O Error で読み書きができず、再起動後も RAID を開始できなかったので、正常な HDD の中には データが破損せずに確実に残っている ハズ。
- 一部ダーティーキャッシュが同期されていないとかあるかもしれないけど、激しくディスクアクセスするようなシステムじゃないので可能性も影響も少。
- ただ、正常な HDD に bad block があるとか言っているから、経年劣化により読みだせない領域等が無いかはちょっと心配。
- この障害の10カ月ほど前に
/dev/sdb
のディスクが故障したことがある。- この時は RAID 自体に特に不具合なく、 HDD を交換しただけだった。
- 1年で HDD が2本も故障した。やはり寿命か。
- 正常な HDD もいつ壊れるかわからない。3本残った内の1本でも壊れればおしまい。
- バックアップシステムは永遠の TBC (To be constructed) なので存在しない。
- 奇跡的に手動でバックアップを取った HDD を見つけたけど、数年前のバックアップな上、データ容量的に一部のバックアップに留まっているので本当に最終手段。
データ復旧対応
バックアップ作成
という訳で何よりも最優先はバックアップの取得となる。あれこれ試行錯誤しているうちに、残っているデータを破壊してしまっては元も子もないし、正常な HDD もいつ寿命を迎えるかわからない・・・
幸いなことに、 Kubernetes のストレージとして使おうかなと思って買っておいた同型の HDD が丁度3本あったのでこれをバックアップへ転用することにする。
バックアップは確かこんな感じで取ったハズ。 Enter キーを押す前に「if と of を間違えたらアウト・・・」と5回ぐらいつぶやいてから実行したような気がする。
# dd if=/dev/sda of=/dev/sdX bs=1024M status=progress
HDD 1本あたり17時間くらい掛かったと記憶。大体160MB/sくらい。3本をシーケンシャルにバックアップすると2日以上掛かってしまう。ここは正常な HDD が故障しないようにと完全なお祈りタイムだ。
バックアップした HDD には、それぞれどの HDD のバックアップを取得したのかを付箋に書いて張っておく。
無事、正常な HDD 3本のバックアップを取れたので、この後は崩壊した RAID からデータをサルベージするための試行錯誤を行っていく。
データサルベージ
概要
結論から言うと、崩壊した RAID 内のデータにアクセスできるようになるまで障害発生から丸っと1か月かかった。だって30TBものデータ領域を持つ RAID の復旧だもの・・・データコピーだけでも時間がかかるし、それなりに機材の購入が必要で待ち時間が多かった。
いろいろ試行錯誤したが、最終的に採った戦略は次のように「仮想マシンで RAID5 の正常な Superblock を作成し、自宅鯖の HDD に移植する」方式にした。
- Proxmox VE でデータサルベージ用の仮想マシンを作成する。
- 10TB の仮想ディスクを4本作れて、スナップショットも取れるデータストアを用意する。
- データストアのために別途 10TB の HDD を5本用意し、 ZFS で RAID0 を組んだ。
- が、実際にスナップショットを取ろうとしたらディスク容量不足だったので、更に1本追加して計6本で約 60TB のデータストアを作った。
- 当初はバックアップした HDD の内容を仮想ディスクにコピーして、そこから試行錯誤しようと思ったのでスナップショットを取れることが重要だった。
- しかし、機材不調によりコピーに何度も失敗したのでこのやり方を止めた。
- 最終的にスナップショットはあまり使わなかった。
- 10TB の仮想ディスクを4本作成する。
- 仮想マシンに 10TB の仮想ディスク4本を接続し、 md-raid で RAID5 を構成する。
- 仮想マシンの RAID5 のリビルド完了を待つ。
- リビルドが完了したら、3番目の HDD (自宅鯖で物理故障した
/dev/sdc
相当) を remove する。 - 1, 2, 4番目の HDD (それぞれ自宅鯖の
/dev/sda
,/dev/sdb
,/dev/sdd
相当) の RAID の superblock をダンプする。 - ダンプした superblock を自宅鯖にコピーし、
/dev/sda
,/dev/sdb
,/dev/sdd
にそれぞれ書き込む。 - 自宅鯖の RAID を再開し、マウントする。
復旧用仮想環境構築
概要のこの辺の話。
- Proxmox VE でデータサルベージ用の仮想マシンを作成する。
- 10TB の仮想ディスクを4本作れて、スナップショットも取れるデータストアを用意する。
- データストアのために別途 10TB の HDD を5本用意し、 ZFS で RAID0 を組んだ。
Proxmox VE は個人の検証環境として、今回障害が発生した自宅鯖とは別のマシンで既に運用中なので詳細は略。
ただ、 Proxmox VE は WebUI からは RAID0 のデータストアを構築できないようになっていたので注意が必要だった。 ZFS on Linux - Proxmox VE に記載されている通りにやればいいだけだったけれども。気が向けば別記事で書く。
仮想ディスク作成
概要のこの辺の話。
- 10TB の仮想ディスクを4本作成する。
まずは自宅鯖の HDD のディスクサイズを確認する。
# fdisk /dev/sda <<< p
(略)
Created a new DOS disklabel with disk identifier 0x3d6c764d.
Command (m for help): Disk /dev/sda: 9.1 TiB, 10000831348736 bytes, 19532873728 sectors
Disk model: 0EFAX-68LHPN0
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0x3d6c764d
Command (m for help):
10000831348736 bytes
とあるので、これを 1,073,741,824 (1073741824 = 1024^3) で割る。丁度 9,314GiB となったけど、他のディスクでも割り切れるのかはわからない。
Proxmox VE にて仮想ディスク4本をそれぞれ計算した 9,314GiB として作成する。
復旧用 RAID 構築
概要のこの辺の話。
- 仮想マシンに 10TB の仮想ディスク4本を接続し、 md-raid で RAID5 を構成する。
- 仮想マシンの RAID5 のリビルド完了を待つ。
作成した仮想ディスクを、復旧用の仮想マシンに接続して仮想マシンを起動する。
仮想マシンが起動したら、 fdisk /dev/sdX <<< p
と打って 10000831348736 bytes, 19532873728 sectors
のあたりが一致していることを確認。仮想ディスクのデバイス名は自宅鯖のデバイス名と一致しないので混乱しないように整理しながら慎重に進めよう。
仮想ディスクのサイズに問題がなければ、 RAID を構築する。
# mdadm --create salvage --level=5 --raid-devices=4 /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi1 /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi2 /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi3 /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi4 --data-offset=131072
ここでは --data-offset=131072
の指定が肝だった。これは自宅鯖の正常な HDD を mdadm --examine /dev/sdX
したときに出力された Data Offset : 262144 sectors
の半分の値なのだが、どういう理由で --data-offset=262144
ではなく --data-offset=131072
なのかわかっていない。
このコマンドを実行した後、自動的にリビルドが開始される。
この間に mdadm --examine /dev/sdX
を実行し、自宅鯖の HDD で確認した結果と比較して次の項目が一致していることを確認しておく。
- Version : 1.2
- Raid Level : raid5
- Raid Devices : 4
- Avail Dev Size : 19532611584 (9313.88 GiB 10000.70 GB)
- Array Size : 29298917376 (27941.63 GiB 30002.09 GB)
- Data Offset : 262144 sectors
- Super Offset : 8 sectors
- Internal Bitmap : 8 sectors from superblock
- Layout : left-symmetric
- Chunk Size : 512K
確認が終わったらあとはリビルドが完了するまで正座待機。
復旧用 RAID を障害機の状態に合わせる
概要のこの辺の話。
- リビルドが完了したら、3番目の HDD (自宅鯖で物理故障した
/dev/sdc
相当) を remove する。
リビルドが完了したら、自宅鯖で障害が起きた HDD と同じナンバーの仮想ディスクを mdadm --remove
する。私は初動で mdadm --detail /dev/md0
をする前に OS を再起動してしまったため、故障した HDD が本当に RAID の3番目のディスクか確証を持てていなかったが、 sda ~ sdd まで順番に認識されているだけと思い込むことにして作業を進めた。
仮想マシンで HDD を remove するコマンドは次の通り。 /dev/sdX
の指定は障害が発生した HDD と仮想マシンのデバイス名の認識によって変わるので注意。
# mdadm --remove /dev/md/salvage /dev/sdX
仮想マシンで mdadm --detail /dev/md/salvage
を実行し、意図した箇所の仮想ディスクが removed
になっていれば OK. イメージとしてはこんな感じ。
Number Major Minor RaidDevice State
0 8 0 0 active sync /dev/sda
1 8 16 1 active sync /dev/sdb
- 0 0 2 removed
4 8 32 3 active sync /dev/sdc
復旧用 RAID の Superblock をダンプ
概要のこの辺の話。
- 1, 2, 4番目の HDD (それぞれ自宅鯖の
/dev/sda
,/dev/sdb
,/dev/sdd
相当) の RAID の superblock をダンプする。
RAID の Superblock をダンプする前にまずは RAID を停止しておきましょう。
# mdadm --stop /dev/md/salvage
RAID を停止したら dd コマンドで各仮想ディスクの RAID の Superblock をダンプしていく。ここでは、 sdX
を仮想ディスクのデバイス名、 sdY
を自宅鯖の対応する HDD のデバイス名とする。
# dd if=/dev/sdX of=salvage_raid_superblock_sdY.bin bs=12K count=1
これを remove した仮想ディスク以外の仮想ディスクに対して行う。
bs=12K
となる理由はよくわかってない・・・ RAID superblock formats - Linux Raid Wiki によると、次のように記載されているので bs=4K
が適切と思ったけど、それで作ったダンプファイルだと自宅鯖の HDD に書き込んでも mdadm --examine
の結果が書き込む前と変わらなかったんだよね・・・
Sub-Version Superblock Position on Device 0.9 At the end of the device 1.0 At the end of the device 1.1 At the beginning of the device 1.2 4K from the beginning of the device
bs=12K
とした理由はなんとなくの勘なんだけど、 bs=12287
としたときと bs=12288
としたときで mdadm --examine
の結果が変わったのでそんなにハズレでもないのかなと思っている。
■ bs=12287
の時 (エラーになる)
# dd if=/dev/sdX of=salvage_raid_superblock_sdY.bin bs=12287 count=1
# mdadm --examine salvage_raid_superblock_sdX.bin
mdadm: No md superblock detected on salvage_raid_superblock_sdY.bin
■ bs=12288
の時 (結果が出力される)
# dd if=/dev/sdX of=salvage_raid_superblock_sdY.bin bs=12288 count=1
# mdadm --examine salvage_raid_superblock_sdY.bin
salvage_raid_superblock_sdX.bin:
Magic : a92b4efc
Version : 1.2
Feature Map : 0x1
Array UUID : c8b39bbf:bb058499:77cf0b3b:ec0bed37
Name : raid-rebuild-test-02:salvage
(以下略)
自宅鯖の RAID をマウント
概要のこの辺の話。
- ダンプした superblock を自宅鯖にコピーし、
/dev/sda
,/dev/sdb
,/dev/sdd
にそれぞれ書き込む。- 自宅鯖の RAID を再開し、マウントする。
まずは仮想マシンでダンプした RAID の Superblock である salvage_raid_superblock_sdY.bin を全て自宅鯖に転送する。転送方法は scp でも ftp でも USB メモリでも何でもよい。
自宅鯖の RAID が停止していることを確認する。停止していなければ mdadm --stop /dev/md0
辺りで停止しておこう。
自宅鯖の RAID が停止したら、転送してきた RAID の Superblock を、 RAID を構成する正常な HDD にそれぞれダンプしていく。次のコマンドでは sdY
が正常な HDD のデバイス名となる。
# dd if=salvage_raid_superblock_sdY.bin of=/dev/sdY
RAID の Superblock を正常な HDD にダンプした時点で勝手に RAID が開始されているかもしれない。私の環境ではいつの間にか RAID が開始されていた。この時の RAID のデバイス名は /dev/md127
や /dev/md/<mdadm --examine の Name の値>
(この例だと /dev/md/raid-rebuild-test-02:salvage
) になっているかもしれない。
試しにマウントしてみる。手に汗握る瞬間だ。
# mount /dev/md/raid-rebuild-test-02\:salvage /mnt
マウントできたのならひとまずおめでとう。でも安心するのはまだ早い。
試行錯誤や検証を行っている中で、 RAID5 を組みなおすときに HDD の順序を間違えたらどうなるか検証してみたことがあった。結果としては、「そもそもマウントができない」ケースと「マウントはできるがファイルが壊れている」ケースを確認できた。
つまりマウントができてもファイルが壊れていないことを確認するまでは安心できない。とりあえず数十MBクラスのファイルが壊れていないことを確認できればいいんじゃないだろうか。知らんけど。
データサルベージ
マウントができ、ファイルの破損がないことの確認までできたのなら後は良しなにデータを救い出していこう。
別 HDD や別マシンにコピー、あるいは故障した HDD の代わりを追加して RAID を完全復旧するのも良いでしょう。ただしここも無事に完了するまでお祈りタイムですがね!
まとめ
事前にやっておけばよかった事
- しっかりと定期的にバックアップを取っておくこと
わからなかった事
- 障害発生時に正常なディスクが全て Spare 扱いになってしまった理由がわからなかった。
正常なディスクの I/O も止まってしまったのであれば、 Spare とマークする事すらできないはずではないのか?再起動後、レスキューモードに入った時点で書き込み可能になったとしても、正常な HDD が3本と故障した HDD が1本あるだけなのだから、 Spare とマークせずに普通に RAID を開始できるのではないだろうか・・・ -
mdadm --create
する際に--data-offset=131072
と指定する必要があった理由がわからなかった。
なぜmdadm --examine
で表示されるData Offset
の半分の値なのか・・・ - RAID の Superblock をダンプするのに
bs=4K
ではなくbs=12K
(?) とする必要があった理由がわからなかった。
振り返り
- RAID の中のデータを見れなくても、データは正常な HDD の中に確実に残っているという確信があったのはよかった。
っていうかそれが無かったら諦めてた。 - 富豪戦略を採ったせいで 10TB の HDD が12本もある逸般の誤家庭になってしまった。文鎮化した HDD も含めると14本。
- なお、サルベージの為に購入した HDD は、新しく NAS を構築しそちらに組み込む模様。
- そのうえで現行の NAS をバックアップに降格させることで、バックアップシステムは永遠の TBC (To be constructed) 問題を解決する予定。
- 暫定的とはいえ、 HDD 6本の RAID0 を作った事と、更にその中に RAID5 を構築したことは我ながら意味不明すぎて笑った。
- もうちょっとさっくりと記事を書くつもりが長くなってしまった。
-
echo idle > /sys/block/md0/md/sync_action
ってやってれば一発で直ったんじゃないか説: linux - mdadm: drive replacement shows up as spare and refuses to sync - Server Fault
おしまい。