SSD Nodes Learn 🎉 VPS $5.50/月〜
ガイド Matt Connor著者 Matt Connor

小規模VPSのZFS scrubはどの頻度で実行する?

ZFS scrubは割り当て済みブロックを読み取り、チェックサム不一致を検出します。単一デバイスのVPSプールでは修復できないため、適切な実行頻度と限界を解説します。

ZFS scrub の実際の動作

ZFS scrub はプール内の割り当て済みブロックをすべて読み取り、チェックサムを再計算して、親ブロックポインターに保存されたチェックサムと比較します。両者が一致しない場合、ZFS はプールが保持する冗長データからブロックを修復します。ZFS の他の処理でこの役割を担うものはありません。通常の読み取りで検証されるのは、実際にアクセスしたブロックだけです。そのため、2 年間開いていないファイルは、scrub が読み取るまで検証されません。

scrub は、他のファイルシステムで必要になるオフライン修復パスである fsck ではありません。ZFS はディスク上の形式を破損した状態のままにしないため、構造修復の段階はありません。すべての書き込みは新しい場所に行われ、プールのルートポインターである uberblock は最後に更新されます。scrub はデバイス全体も読み取りません。割り当て済みブロックだけを読み取ります。そのため、ほぼ空のプールでは数分で完了しますが、同じプールが 80% 使用されている場合は大幅に時間がかかります。

scrub は、ZFS で最も低い I/O 優先度で実行されます。Linux では zfs_vdev_scrub_max_active のデフォルト値が 2 であるため、各 vdev(virtual device。ZFS が 1 つの単位として扱うディスク群)につき、scrub の読み取りは最大 2 件まで同時に実行されます。zfs_scrub_min_time_ms のデフォルト値は 750 です。これは、トランザクショングループのフラッシュ間で同期スレッドが scrub 処理に費やす最小時間です。トランザクショングループは、ZFS が書き込みをまとめて定期的にコミットする単位です。アイドル状態のマシンでは、scrub がディスク全体を使用します。負荷がかかると、scrub は処理を譲ります。デバイスが 1 台または 2 台しかないプールでは、処理を譲る先がありません。そのため、60 台のドライブを搭載した大型シャーシよりも、このような環境ではスケジュール設定が重要になります。

自己修復できないプールをなぜスクラブするのですか?

小規模なプールでは、この点が以降の判断をすべて左右します。冗長性がない場合、スクラブは破損を検出できますが、修復はできません。 VPS の単一仮想ディスクは、ミラーもパリティもないプールです。ZFS は不良ブロックを読み取り、チェックサムの不一致を検出して CKSUM 列に記録し、ファイル名を示すところまでしか実行できません。再構築元となる 2 つ目のコピーがないためです。

知っておくべき部分的な例外が 2 つあります。ZFS はデフォルトでメタデータの追加コピーを保存します(redundant_metadata=all)。これはデバイス上の別の領域に書き込まれるため、1 台構成のプールでも、破損したディレクトリエントリやブロックポインターをスクラブで修復できる場合があります。また、copies=2 を設定したデータセットは、データブロックを 2 コピー保持します。必要な容量は 2 倍になります。ただし、いずれもデバイス自体が利用できなくなった場合には機能しません。copies プロパティのドキュメントも、まさにこの点について警告しています。ストライププールを作成し、copies=2 を設定しただけで、冗長性があると考えてはいけません。

したがって、単一デバイスのプールでスクラブが提供するものは、早期かつ正確な通知です。バックアップにそのファイルの正常なバージョンが残っている間に、サイレントな破損を zpool status -v 内のファイル名として把握できます。これはバックアップを実施すべき理由であり、スクラブを避ける理由ではありません。ポイントインタイムイメージと、実際に別の場所へ保存したコピーの違いをまだ整理できていない場合は、VPS スナップショットがバックアップではない理由から確認してください。スクラブの結果が役立つのは、別の場所に完全なコピーが保持されている場合だけです。

何も検出しないスクラブも結果の 1 つです。これから信頼して使用するデータが完全な状態であることを示します。これは、リストアや移行の前に確認したい情報です。

小規模な VPS プールはどのくらいの頻度でスクラブすべきですか?

月次を標準にするのが適切です。パッケージもすでにこの頻度を前提にしています。Debian と Ubuntu には、毎月第 2 日曜日に正常なプールをスクラブする cron ジョブが含まれています。FreeBSD の periodic システムは日数のしきい値に基づいて動作し、daily_scrub_zfs_default_threshold の既定値は 35 です。マニュアルでは 5 週間と説明されています。

負荷の高い小規模プールでは、通常、週次のスクラブは効果よりコストが上回ります。デバイスが 1 台または 2 台の場合、スクラブはアプリケーションと同じキューを使用し、処理を引き受ける余裕のあるデバイスもありません。VPS では I/O の割り当て量が有限です。そのため、スクラブが消費する読み取り分だけ、データベースが利用できる読み取りが減ります。そのコストに対して、週次のスクラブで得られるのは、修復できない障害を最大 3 週間早く検知できる可能性にすぎません。スクラブの負荷が小さい場合にだけ、この選択に意味があります。

所要時間を測定してから判断してください。手動で 1 回スクラブを実行し、完了までの時間を確認します。

  1. 負荷の低い夜に sudo zpool scrub tank を実行し、zpool status からの合計所要時間を記録します。
  2. 1 時間を大幅に下回る時間で完了し、サーバーが夜間にアイドル状態になる場合は、週次でも許容できます。
  3. プールがネットワークトラフィックを処理している間に数時間かかった場合は、月次のままにし、パッケージに含まれるジョブに任せます。
  4. プールの規模が明らかに大きくなった場合は、再度所要時間を測定します。スクラブの所要時間はディスク容量ではなく、割り当て済みデータ量に応じて変化するためです。

どの頻度を選んでも、ほかの定期的なサーバー作業と一緒に記録してください。スクラブは、パッケージのアップグレードやログローテーションと同じ一覧で管理します。Linux サーバーの月次メンテナンスチェックリスト を参照してください。

スクラブを開始、一時停止、停止する

sudo zpool scrub tank
sudo zpool status tank

一時停止と停止は異なる操作です。間違った方を選ぶと、数時間分の作業を繰り返すことになります。

sudo zpool scrub -p tank
sudo zpool scrub tank
sudo zpool scrub -s tank

-p は一時停止します。一時停止状態と進行状況は定期的にディスクへ同期されるため、スクラブを一時停止したまま export や再起動を実行しても状態は維持されます。プールは、スクラブが一時停止した状態で再び利用可能になり、再開を待ちます。zpool scrub を再度実行すると、ディスクに書き込まれた最後のチェックポイントから再開します。-s はスクラブを停止します。その後に開始するスクラブは最初から実行されます。1 時間ほどディスクを解放したい場合は -p を使用します。スクラブを終了したい場合は -s を使用します。

さらに、知っておくと便利なフラグが 2 つあります。-w は、スクラブが完了するまで戻りません。スクリプト内で次の処理を早く開始させたくない場合に使用します。-e は、zpool status -v が報告した既知のデータエラーがあるファイルだけをスクラブします。バックアップから復元したファイルが正常になったことをすばやく確認できます。

ZFS は、プールごとに一度に 1 つのスクラブまたは resilver(デバイス交換後に実行される再構築)だけを実行します。どちらも I/O 負荷が高いためです。デバイスの resilver 中は、スクラブは順番を待ちます。

scrub 実行中に zpool status を読む方法

sudo zpool status tank を実行し、他の環境の数値と照合せず、自分の環境の数値を読み取ります。scrub 中は、scan: 行にスキャン済みの値、発行済みの値、合計値、修復済みの値、進捗率、残り時間の推定値が表示されます。

Scanned はメタデータ処理の段階です。ZFS がブロックツリーを走査し、読み取りが必要なアドレスを収集します。Issued はデータ処理の段階です。デバイスに実際に送信された読み取りを、ディスク上の順序に並べたものです。scrub では読み取りを並べ替えるため、2 つのカウンターがあります。実際の進捗を追跡するのは Issued です。開始直後は Scanned が Issued を大きく上回るため、時間の推定値はほとんど参考になりません。最初の 10% が完了してから判断してください。

Repaired は、正常なコピーから書き直されたバイト数です。冗長性のないプールでは、scrub で何が検出されても 0 のままです。これは、先に説明した点を監視可能な数値で示したものです。

次に、デバイスごとの列を確認します。READ と WRITE は、デバイス自体が報告した I/O エラーの数です。CKSUM はチェックサム検証に失敗したブロックの数です。scrub は、この CKSUM 列を埋めるために実行します。正常に見えるデバイスで CKSUM が 0 以外なら、実際のエラーです。データは返されましたが、内容が正しくありません。

最後の行が判定結果です。errors: No known data errors が正常終了です。それ以外の場合は sudo zpool status -v tank を実行してください。最後に完全な scrub が完了してから発生したデータエラーの一覧が、影響を受けたファイル名を含めて表示されます。該当するファイルをバックアップから復元し、sudo zpool clear tank を実行してカウンターをリセットしてから、scrub を再実行します。完全な scrub を実行するたびにこの一覧は再構築されます。そのため、正常に完了した full scrub の後に存在しないファイル名は、実際に解消されています。

ホストで有効になっている定期 scrub ジョブはどれですか?

ジョブが存在すると決めつけないでください。また、1 つだけだとも決めつけないでください。仕組みはプラットフォームとパッケージによって異なります。プール形式はどの環境でも同じであるため、周辺ツールも同じだと思いがちですが、ここで重要なのはFreeBSD と Linux での ZFS の提供方法の違いです。

FreeBSD では、ジョブは periodic システムにあります。/etc/periodic.conf で次の値を設定します。

daily_scrub_zfs_enable="YES"
daily_scrub_zfs_pools="tank"
daily_scrub_zfs_default_threshold="35"

daily_scrub_zfs_pools はプール名をスペースで区切ったリストです。空のままにすると、すべてのプールを scrub します。daily_scrub_zfs_default_threshold は、プールごとのしきい値を設定していない場合に scrub の間隔として使用する日数です。マニュアルではデフォルト値として 35 が示されています。daily ジョブは毎日実行され、しきい値を超えた場合にだけ scrub を開始します。

Linux では、使用しているディストリビューションの ZFS パッケージによって異なります。また、一部のシステムでは両方の仕組みが同時に存在します。プール単位の systemd timer として zfs-scrub-monthly@tank.timer および zfs-scrub-weekly@tank.timer があり、プールごとに有効化します。Debian と Ubuntu には /etc/cron.d/zfsutils-linux も含まれています。これは毎月第 2 日曜日にスクリプトを実行し、ONLINE 状態のすべてのプールを scrub します。何が設定されているかを確認してから追加してください。

systemctl list-timers 'zfs-*'
ls /etc/cron.d/ | grep -i zfs
sudo zpool history tank | grep scrub

zpool history が実際の状況を正確に示します。プールが実際に開始した scrub と、その日付を記録するためです。1 か月に 2 回 scrub が実行される場合は、両方の仕組みが有効になっているため、どちらかを無効にしてください。timer を有効にするには、次を実行します。

sudo systemctl enable --now zfs-scrub-monthly@tank.timer

空き容量は、どのチューナブル設定より重要です

小規模なプールのスクラブ時間は、割り当て済みデータの量と、その分散状態で決まります。プールを満杯にすると、どちらも悪化します。

OpenZFS では、プールの空き容量を 10% 超に保つことが推奨されています。これを下回ると、アロケーターが処理するチャンクである metaslab が 4% の空き容量しきい値を超え始め、アロケーターは first-fit から best-fit に切り替わります。best-fit は CPU 負荷が大幅に高くなります。書き込みレイテンシが増加し、断片化も進みます。さらに、同じ量のデータがより多くの小さな読み取りとして処理されるため、次のスクラブは一段と遅くなります。

したがって、最初に行うべき対策はチューナブル設定の変更ではありません。不要なものを削除することです。ZFS サーバーでは古いスナップショットが通常の原因です。次に、削除されていない Docker イメージとレイヤーアップグレード後に残ったカーネルパッケージが続きます。ほかの作業を行う前に zfs list -o space を実行してください。これにより、スナップショットが保持している容量と、ライブデータが使用している容量を分けて確認できます。

次に、設定項目を簡単に確認します。Linux では、現在の値を次のコマンドで確認できます。

cat /sys/module/zfs/parameters/zfs_scrub_min_time_ms
cat /sys/module/zfs/parameters/zfs_vdev_scrub_max_active

FreeBSD では、同じパラメーターを sysctl で確認できます。自分の環境の値は sysctl -a | grep scrub で調べてください。値を上げるとスクラブは早く完了しますが、アプリケーションは遅くなります。値を下げると逆の結果になります。デバイスが 1 台または 2 台のプールでは、どの設定でも両方を実現することはできません。分けられるキューが 1 つしかないためです。チューナブル設定だけで設計上の問題が解決することはほとんどありません。月次スクラブが負荷になる場合、プールが満杯に近すぎるか、デバイスが遅すぎるというのが実際の状況です。チューナブル設定は問題の場所を移すだけです。

スクラブ時間はresilver時間の目安です

resilverはスクラブと同じ走査を行います。割り当て済みのブロックを読み取り、検証し、交換デバイスに不足しているブロックを書き込みます。そのため、スクラブにかかる時間は、再構築にかかる時間と、その間プールが冗長性を低下させた状態で稼働する時間を、最も正確に見積もる目安になります。

ZFSは、スクラブよりもresilverを優先して処理するため、通常は同じプールのスクラブよりも再構築のほうが早く完了します。スクラブ時間は、安全側に見積もった上限として扱ってください。スクラブに9時間かかる場合は、同程度の再構築時間を想定します。その時間内に2台目のデバイスが故障すると、プールを失うことも理解しておく必要があります。これが、1つの広いraidzグループではなくミラー構成のペアを選ぶ実務上の理由です。ZFSがRAID 5の代わりに使用するパリティ構成であるraidzは、生存しているすべてのデバイスを読み取って再構築するためです。

単一デバイスのプールでは、resilverは発生しません。デバイスが失われると、プールも失われます。復旧時間はリストア時間になるため、代わりにリストアにかかる時間を測定してください。一度も実行していないリストアは、復旧計画とはいえません。

ディスクを借りる場合の変更点

VPS では、ブロックデバイスは仮想化されています。ハイパーバイザーがボリュームを提示し、その下にはローカル NVMe がある場合もあれば、独自にパリティを持つレプリケーション済みのネットワークボリュームがある場合もあります。これにより、スクラブには2つの影響があります。

1つ目は、プラットフォーム側の冗長性が ZFS から見えず、ZFS も利用できないことです。プラットフォームが下位層でメディアエラーを修復しても、ZFS はその問題を認識しません。プラットフォームが誤ったブロックを渡した場合は、ZFS がそれを検出します。しかし、正しいコピーはその境界の反対側にあるため、ZFS は修復できません。

2つ目は、通常、仮想ディスクの下にあるデバイスの SMART(自己監視・分析・レポート技術)データを読み取れないことです。そのため、VPS でのディスク健全性監視に必要な早期警告を、まったく利用できない場合があります。スクラブで表示される CKSUM カウンターが、利用者側で管理できる主なシグナルになります。

ZFS に単なる報告ではなく修復も行わせるには、同じインスタンス内に複数のデバイスが必要です。これはチューニングではなく、構成を決める段階での判断です。通常の VPS ではなくストレージ VPSを選べば容量は確保できますが、独立した2台のデバイスが提供されるかどうかはプランによって異なります。lsblk を実行し、実際には1つのボリュームを分割しただけの2つのスライス上にミラーを構築していないことを確認してください。当社が提供するのは Linux および FreeBSD サーバーであり、管理型 ZFS アプライアンスではありません。そのため、スクラブのスケジュール設定とバックアップの実行は利用者が担当します。これがトレードオフです。プールを完全に制御できる一方で、その保守もすべて利用者が担います。

FAQ

ZFS プールを VPS でスクラブする頻度はどのくらいですか?

ほとんどの小規模なプールでは、月1回が適しています。Debian と Ubuntu では第2日曜日に実行する cron ジョブが、FreeBSD の periodic システムでは35日間のデフォルトしきい値が設定されているためです。週1回が妥当なのは、スクラブにかかる時間を測定し、ほかの処理をしていないサーバーで短時間に完了することを確認した場合だけです。デバイスが1台または2台のビジーなプールで毎週スクラブを実行すると、毎週アプリケーションの I/O を消費する一方、早期警告を数週間早く得られるだけです。

1台のディスクだけで構成した ZFS プールをスクラブしても意味がありませんか?

いいえ。ただし、何が得られるかを明確に理解しておく必要があります。冗長性がない場合、スクラブは破損を検出できますが、修復はできません。ただしメタデータについては、ZFS がデフォルトで追加のコピーを保持しています。得られるのは zpool status -v に表示される、破損したファイルの一覧です。別の場所に正常なコピーがまだ存在するうちに、ファイルを復元できます。スクラブによって復元すべきファイルを正確に特定できるため、適切な対応はバックアップを改善することです。

ZFS のスクラブを一時停止して、後で再開できますか?

はい。zpool scrub -p tank で一時停止できます。一時停止状態と進行状況は定期的にディスクへ書き込まれるため、export や再起動の後もスクラブは一時停止したままになります。zpool scrub tank を再度実行すると、最後のチェックポイントから再開します。この用途で zpool scrub -s tank は使用しないでください。-s はスクラブを停止するため、次回のスクラブは最初から開始されます。

ZFS のスクラブが非常に遅いのはなぜですか。速度を上げることはできますか?

スクラブにかかる時間は、ディスク容量ではなく、割り当て済みデータ量と断片化に左右されます。プールの使用率が90%を超えると遅くなります。空き容量が4%未満の metaslab では、allocator が first-fit から best-fit に切り替わり、その結果生じる断片化によって、スクラブが多数の小さな読み取りになります。通常は、チューナブルを変更するより空き容量を確保するほうが効果的です。zfs_scrub_min_time_ms または zfs_vdev_scrub_max_active の値を増やすと、スクラブに割り当てるキューの割合を大きくできます。ただし、デバイスが1台または2台のプールでは、その分だけアプリケーションの処理に使える割合が減ります。