[RECOVERY]INTERMEDIATE

深夜にディスクが1本死んだときの手順

初めて本番でディスク故障のアラートを受けたのは深夜2時でした。幸いミラー構成で、パニックになる必要はなかったのですが、当時の自分は`zpool status`の読み方に自信が持てず、無駄に時間を溶かしました。zpool offlineからzpool replaceによる復旧、resilver完了確認までを実機のコマンド出力で追います。

初めて本番環境でディスク故障のアラートを受けたのは深夜2時でした。ミラー(RAID1相当)構成だったので実際にはパニックになる必要は何もなかったのですが、当時の自分はzpool statusの出力の何が正常で何が異常なのか自信が持てず、無駄に時間を使いました。ミラー構成のディスク故障は、ストレージ運用の中でも最もよくある障害シナリオです。zpool statusが何を報告しているのかを正しく読み、正しい順序で対処すれば、単純な片肺障害を不要なダウンタイムに変えずに済みます。

この記事では、2本のディスクによるミラープールで片方のディスクが失われるケースを実際に再現し、検知から復旧までの一連のコマンドと出力を追いかけます。

健全な状態を確認する

まず、正常なミラープールが zpool status でどう見えるかを押さえておきます。

pool: tank
state: ONLINE
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            disk1   ONLINE       0     0     0
            disk2   ONLINE       0     0     0

state: ONLINE に加えて、mirror-0 とその配下の各ディスクもすべて ONLINE になっている点がポイントです。ZFSでは、プール全体の状態は常にその中で最も悪い状態のVDEV/デバイスに引きずられます。つまり、後で見るように1本のディスクが OFFLINE になるだけで、プール全体の stateDEGRADED に変わります。

FLOWSCENErecovering-a-degraded-zfs-mirror
tankvdev-1vdev-2disk1disk2disk3disk4
$ truncate -s 512M /root/zfs-scenario-template/disk1.img /root/zfs-scenario-template/disk2.img && zpool create tank mirror /root/zfs-scenario-template/disk1.img /root/zfs-scenario-template/disk2.img
(no output)

ループバックファイル2本でミラープールを作成する

offlineとFAULTEDは全く違う

上のパネルの step-3-simulate-fault では、意図的にディスクを1本切り離しています。ここで実務上重要なのは、故障したディスクをいきなり物理的に抜く前に zpool offline で明示的に切り離す、という順序です。

理由は2つあります。

  1. ZFS側の状態遷移を確定させるため。 ディスクがまだファイルシステム上で応答している(あるいは応答しなくなりつつある)状態でいきなり抜くと、ZFSがI/Oタイムアウトやチェックサムエラーの蓄積を経て初めて異常を検知するまで、プールが不安定な遷移状態に留まることがあります。zpool offline は「このデバイスはこれから触ります」という意図をZFSに明示的に伝える操作で、状態は即座に OFFLINE として確定します。
  2. メンテナンス作業そのものを安全にするため。 ホットスワップに対応していない環境や、対象のディスクを取り違えるリスクがある環境では、先にoffline化してからLEDやスロット番号で対象を再確認し、物理的な取り外しに進む方が事故が少なくなります。

zpool status の出力で status: 行に "One or more devices has been taken offline by the administrator." と表示されるのは、まさにこの操作が管理者による意図的なものであることをZFS自身が記録しているからです。ディスクの物理故障やI/Oエラーによる FAULTED とは異なり、OFFLINE は「壊れた」ではなく「切り離した」を意味します。

ミラーは動き続けている

step-3-simulate-fault:after の出力を見ると、プール全体は DEGRADED になっていますが、errors: No known data errors は変わらず、action: 行には次のように書かれています。

Sufficient replicas exist for the pool to continue functioning in a degraded state.

これがミラー構成の本質的な価値です。冗長性のあるVDEVでは、1本のディスクを失っても読み書きは継続でき、データも失われません。DEGRADED は「今すぐデータが失われる」という警告ではなく、「冗長性の余裕を使い切りつつある」という警告として読むべきです。

とはいえ、DEGRADED のまま長時間放置してよい理由にはなりません。ミラーが片肺の間は、残ったディスクにさらに障害が起きた場合の保護がなくなっています。検知したら速やかに復旧作業に移るのが原則です。

zpool replaceで新しいディスクに置き換える

step-4-recover では、失われたディスクの代わりとなる新しいディスクを用意し、zpool replace で置き換えています。

zpool replace tank disk1 disk1

実運用では、新しいディスクは通常もとと同じデバイスパス(あるいは物理的に別スロットの新しいディスク)になります。重要なのは、zpool replace <pool> <old-device> <new-device> の第2引数(old-device)はプール内でどのVDEVを対象にするかを識別するための指定であり、そのパスに実体のファイル/デバイスが存在している必要はないという点です。すでに offline にして取り外し済みのディスクを指定しても、ZFSはプールのメタデータからどのVDEVを指しているか判断できます。

resilverの進行を確認する

step-5-zpool-status-recovered では、zpool status の出力に resilver in progress というセクションが現れます。

scan: resilver in progress since ...
      110K scanned at 110K/s, 110K issued at 110K/s, 110K total
      178K resilvered, 100.00% done, no estimated completion time

resilverとは、生き残っているディスク(この場合は disk2)からデータを読み出し、新しく投入したディスクに書き戻していく処理です。従来型RAIDの「全ブロックを機械的にコピーするリビルド」とは異なり、ZFSのresilverは実際に使用されているブロックだけを対象にするため、プールの使用率が低ければリビルド時間も短くて済みます。この検証環境ではプールがほぼ空のため、resilverはごく短時間で完了します。実運用でTB単位のデータが入ったプールでは、resilverには数時間〜数日かかることもあり、その間は zpool status でscan行を定期的に確認し、進行が止まっていないかを見ておく価値があります。

resilverが完了すると、replacing-0 という一時的な入れ子のVDEVは解消され、mirror-0 の配下に新しいディスクだけが ONLINE として残ります。最終的に zpool status を再実行し、state: ONLINE に戻ったこと、errors: No known data errors が維持されていることを確認して、復旧作業は完了です。

今なら深夜2時でも慌てない

  • ミラーVDEVでのディスク1本の喪失は、ZFSにとって想定内の障害です。冗長性がある限りプールは動き続けます
  • 可能な限り、物理的に取り外す前にzpool offlineで明示的に切り離しましょう。ZFSの状態表示が即座に確定します
  • DEGRADEDは「今すぐ何かが壊れる」ではなく「冗長性の余裕がない」状態です。放置せず速やかにzpool replaceしてください
  • resilverの進行状況はzpool statusscan:行で追跡できます。完了を確認してから作業完了とみなしましょう

あの深夜以来、zpool statusの出力を落ち着いて読めるようになりました。焦ってzpoolコマンドを乱打するより、まずstatus:action:の行を読むだけで、次に何をすべきかは大抵書いてあります。