ZFS:ストレージプール、トランザクショングループ、同期書き込みのリカバリ

このページの目次

同期書き込みは成功したが、最新の TXG はまだコミットされていない。また、現在のファイルを削除しても、スペースが完全に解放されない。ZFS において、これらの2つの現象はそれぞれリカバリ根拠と共有参照によって説明され、「キャッシュがあるから」という単純な説明では不十分である。

説明すべき現象該当セクション
4台のディスクで任意の2台の故障に耐えられるか?第1~2節:プールと vdev
同期成功後のリカバリ根拠は何か?第3節:TXG と ZIL のタイムライン
SLOG、L2ARC、special vdev は互いに交換可能か?第4節:デバイスの役割
スナップショットがスペースを保持する理由、整合性チェックがバックアップと同等でない理由第5~7節:参照帳とリカバリ能力

1. pool、vdev、dataset の階層

オブジェクト役割混同してはならない概念
poolスペースの割り当てを一元化し、プールレベルの状態を管理するディレクトリ1つに相当するわけではない
トップレベル data vdevデータの割り当てと自身の冗長性を担当する複数のトップレベル vdev が自動的にミラーリングされるわけではない
mirror / RAIDZ vdevメンバーデバイスの冗長レイアウトを構成する冗長性の許容範囲は通常、各 vdev ごとに分析される
filesystem datasetファイルディレクトリ、属性、クォータ、スナップショットなどの管理境界個別のパーティションは不要だが、プールのリソースを共有する
zvolブロックデバイスを公開する volume dataset通常のディレクトリツリーを直接提供するわけではない
snapshot / clone履歴状態の保持 / スナップショットに基づく書き込み可能な派生別の障害ドメインの完全なバックアップに相当するわけではない

プールが2つの2ディスクミラーからなるトップレベル vdev で構成されていると仮定し、グループごとに故障を判断する:

故障の分布各グループにコピーが残っているか?典型的な結果
各グループで1台ずつ故障あり通常、サービス継続可能
同一グループで2台とも故障そのグループにはなしプールが利用不能になる可能性がある

同じ2台の故障でも、位置が異なれば結果が異なる。RAIDZ も同様に、グループごとのレイアウト、実際のエラー、残りのコピー数に基づいて分析する必要がある。詳細はプールと vdev の概念を参照。

2. ソフトウェア層はすべてのリクエストが順次通過するパイプラインではない

ZPL は POSIX ファイル操作を Linux VFS に接続し、DMU はオブジェクト、データバッファ、トランザクションを管理し、SPA および vdev 関連層はストレージプールの割り当てと低レベル I/O を処理する。ARC はキャッシュ機構であり、ZIL は同期意図ログであり、これらを DMU と SPA の間に必須の直列層として描くべきではない。

OpenZFS は Linux 上でカーネル外モジュールを提供しており、DKMS またはディストリビューションのプリコンパイルモジュールを使用してインストールできる。SPL は主に必要なカーネル環境と抽象化を適応させるものであり、あらゆるライセンスの組み合わせを自動的に有効にする法的変換層ではない。OpenZFS は CDDL を使用しており、公開およびパッケージ化についてはライセンスの説明および対象ディストリビューションの方針を参照すること。「決してマージされない」というのは現在の事実に基づかない主張であり、技術的な結論としては不適切である。

ARC と Linux のマップ/ページキャッシュパスとの相互作用は実装バージョンに依存し、ZFS が Linux ページキャッシュを全く関与させないと単純に断言することはできない。通常ファイル、mmap、zvol、ダイレクト I/O も、同じ読み書き関数チェーンに無理やり当てはめるべきではない。

3. TXG:一貫したブロック参照のグループをコミットする

変更はまずメモリ内のオブジェクト状態に入り、トランザクショングループに追加される。TXG を同期化する際、データおよび影響を受けるメタデータパスが書き出され、最後に識別可能な有効なルート状態が確立される。リカバリはブロック整合性チェック、順序、有効な uberblock などのメカニズムに依存しており、すべてのブロックポインタの書き込みが本質的にアトミックであるわけでも、任意のセクタのティアリングが問題ないわけでもない。

TXG は複数の変更を集約してコストを分散する。open、quiescing、syncing などのフェーズにより、異なるグループの作業がオーバーラップ可能になる。タイムアウトパラメータはトリガー条件の一つに過ぎず、ダーティデータの圧力なども同期を促進するため、1回の write を「ちょうど5秒後に1つのアトミックトランザクション」と対応付けることはできない。ファイルシステムトランザクションの境界は、アプリケーションのマルチステップなビジネス境界と自動的に一致するわけではない。

同期リクエストと TXG:まずリカバリ根拠を確立し、その後通常のディスク書き込みを完了する アプリケーション同期書き込み / fsync メモリ内の変更 トランザクショングループ TXG に追加 必要な ZIL レコードをコミット プール内または独立した SLOG に配置可能 同期リクエストは返却可能 リカバリ保証が満たされた TXG を通常ストレージに書き込み 有効な新しいルートをコミット 対応するログを回収可能 再度のリカバリは不要 これは典型的な ZIL パスです。同期済み TXG などの場合はログへの再書き込みは不要です。周期は固定された損失ウィンドウではありません。

同期リクエストは通常、ZIL を使用してクラッシュ後に再実行可能な根拠を確立し、毎回大型の TXG の完全な同期を待つ必要はない。その後、対応するデータは通常の TXG パスを通じて通常ストレージに書き込まれ、リカバリ時には、すでにコミット済み TXG で上書きされていないログが必要な分だけ再実行される。ZIL レコードには書き込みデータが含まれる場合もあれば、すでに書き出されたブロックを参照する場合もあり、「操作名のみを保存し、データを一切保存しない」と言うことはできない。

TXG と ZIL を同じリカバリタイムラインに配置する

すでに安定してコミットされた TXG 100 において、ファイルのある範囲の内容が O であると仮定する。アプリケーションが同期変更 W₁ を実行し、それを N に書き換える。その後、別の範囲の通常非同期変更 W₂ が実行されたが、W₂ に対して同期リクエストは行われなかった。sync=standard であり、ストレージデバイスが書き込みおよび同期の保証に従うものと仮定する。

クラッシュの位置安定したリカバリ根拠これに基づいて保証できること
W₁ の同期リクエストがまだ成功して返されていない少なくとも TXG 100 がある;ログの完全性は進行状況に依存するW₁ を確認済み更新として扱うことはできない
W₁ に必要なログが安定し、同期呼び出しが成功;新しい TXG はまだコミットされていないTXG 100 と再実行可能な W₁ ログ古いルートをリカバリ後、必要なログを再実行し、確認済みの W₁ を保持する
TXG 101 に W₁ が含まれ、安定してコミットされた新しい有効なルートとその参照ブロックW₁ は通常のツリーによってすでに上書きされており、対応するログは回収可能

以下で変更範囲を選択し、同期書き込み、非同期書き込み、TXG コミットをインターリーブする。リカバリ結果は安定したルートとまだ再実行が必要なログから得られ、最新のメモリ内容は自動的にリカバリ根拠にはならない。

図を準備しています
同期書き込みがまだ TXG に含まれていない場合、リカバリはどのように行われるか?

確認済みの同期変更は、古い TXG と必要な ZIL レコードによって回復可能である。新しい TXG によって上書きされて初めて、これらのログは不要になる。非同期書き込みも TXG とともに永続化される可能性がある。

非同期 W₂ を再考する:保証されていないからといって必ずしも消失するわけではない

W₂ の運命は「W₁ の後に発生したから」という理由だけで推論できない。もしそれが有効な TXG によって上書きされておらず、同期保証もない場合、消失する可能性がある。もしある TXG とともに安定してコミットされていれば、保持される可能性もある。非同期とは、アプリケーションがその返却ポイントで同じ永続性保証を得られないことを意味するだけであり、カーネルがそれが必ず消失すると保証するものではない。

このタイムラインは、COW と ZIL がそれぞれ何を供給するかを示している。COW の有効な古いルートにより、システムは一貫したブロック参照のセットに戻ることができる。ZIL は、アプリケーションに対して確認済みだが、まだ最新の通常のツリーに含まれていない同期操作を補完する。ログデバイスの低レイテンシは、後者のリカバリ根拠の確立速度に影響を与えるが、メインストレージが変更を書き出すことを永久に免れさせるものではない。

ログが消失した場合、どちらのリカバリ根拠が成立しなくなるか

まだ再実行が必要な唯一のログコピーが同時に消失した場合、2行目の証明は成立しなくなる。リスクの集合は「どの確認済み操作がまだそのログに依存しているか」によって決定され、固定された壁掛け時計の5秒でも、特定のパラメータ名だけで決定されるものでもない。冗長なログとデバイスの電源断保護の意義は、設計された故障条件下でもリカバリ根拠が存在し続けることにある。

4. ZIL、SLOG、L2ARC、special vdev

名称役割故障時にまず考慮すべきこと
ZIL同期変更のリカバリログ機構確認済みだが TXG で上書きされていない変更をどのようにリカバリするか
SLOGZIL が使用する独立したログデバイスログの冗長性、電源断保護、エラーおよびリカバリパス
ARCメモリキャッシュ(データ、メタデータなどを含む)メモリ圧力、キャッシュヒット率、ダーティデータのスロットリング
L2ARC / cache vdevARC 以外のセカンダリ読み取りキャッシュ消失後は通常、メインストレージから再読み込みされ、唯一のデータソースではない
special vdevメタデータなどの割り当て、設定によっては小データブロックも格納クリティカルアロケーションデバイスであり、いつでも破棄できるキャッシュではない

SLOG は、任意の非同期の大容量ファイル書き込みを継続的な SSD 速度に変えるものではない。それは関連する同期リクエストのレイテンシパスを変更するだけであり、通常ストレージは TXG の書き出しを引き続き受け持つ。バックエンドの排出速度が長期間不足している場合、システムは最終的にスロットリングを行う。デバイスのレイテンシは、標称シーケンシャル帯域幅だけでなく、flush および電源断保護下の実際の挙動を見る必要がある。

ログデバイスを消失させ、さらにクラッシュが発生すると、アプリケーションに対して確認済みだが、まだログによるリカバリが必要な変更が破損する可能性がある。「直近の固定5秒のみが消失し、非同期書き込みは影響を受けない」とは保証できない。実行中、インポート時、ログに冗長性があるかどうか、対応する TXG がコミットされたかどうかによって、結果は変化する。関連するデバイスの役割についてはOpenZFS ハードウェア説明を参照。

sync=standard はアプリケーションの同期リクエストに従い、sync=always は同期要件を拡大し、sync=disabled はこの種の通常の永続性要件を無視する。disabled のパフォーマンスを通常の fsync のパフォーマンスと直接比較することは、異なる保証を比較するものであり、同じ安全条件下でより高速であることを証明するものではない。属性のセマンティクスについては zfsprops(7) を参照。

5. スナップショット、レコードサイズ、スペースの保持

スナップショットは古いブロック参照を保持し、クローンではスナップショットを基に書き込み可能なブランチを生成できる。ファイルが元のブロック A、B を持っており、スナップショット作成後、現在のバージョンが A を A′ に変更したと仮定する。古い A は依然としてスナップショットによって参照されている。現在のファイルを削除しても、A、B が必ずしも回収されるとは限らない。プールの使用量と、あるディレクトリのファイルの論理サイズは、共有、圧縮、スナップショット、メタデータにより異なる。

スペースの帳:512 KiB ファイルがなぜ 640 KiB を保持しているか

モデルを制限する。ファイルは4つの 128 KiB レコード A、B、C、D で構成されており、メタデータ、圧縮、パディング、追加コピーは無視する。スナップショット S を作成後、2つのビューはこれら4つのレコードを共有する。現在のファイルは A を A′ に書き換える。

1回のレコード書き換え:2つのビュー、合計5つのレコードを保持 スナップショット S 現在のファイル A B C D A′ B、C、D は引き続き共有 5 × 128 KiB = 640 KiB 各ビューの論理長は依然として 512 KiB です。メタデータ、圧縮、パディング、追加コピーは無視します。
状態現在のファイルの論理サイズ2つのビューが合計で保持する
スナップショット作成後512 KiBA、B、C、D、合計 512 KiB
A の書き換え後512 KiBA、A′、B、C、D、合計 640 KiB

追加の占有は、履歴の A 依然として参照されていることに由来し、ファイルの論理長が大きくなったからではない。

この時点で現在のファイルを削除しても、S が残っている限り、古い A、B、C、D には依然として参照がある。S を削除して現在のファイルを残す場合、古い A は対応する回収が完了後に解放される。実際の統計には他のオーバーヘッドや共有関係も含まれるため、この数字を直接適用することはできないが、参照帳の推論方法は同じである。⁠ファイルの論理サイズは統計内容のビューを、プールの使用量は保持が必要な実際のストレージを統計する⁠。これにより、スナップショットの作成直後は安価だが、長期間頻繁に書き換えられると多くの履歴ブロックを保持する可能性がある理由が説明される。

レコードサイズ:レイアウト属性は必ずしも毎回のデバイスリクエストサイズではない

recordsize はファイルシステムのデータレコードサイズに関連する属性であり、volblocksize は zvol に使用される。これらは「各アプリケーションの write が必ず同じサイズのデバイスリクエストを発行する」ことを意味するものではない。小範囲のランダム書き換え、圧縮、COW、既存のファイルレイアウトは増幅に影響を与える。属性の変更は、すべての古いファイルを即時書き換えることとして単純に扱うことはできない。チューニングの前に、ワークロードの読み書き範囲と同期頻度を明確にする必要がある。

キャッシュの観測:ヒット率だけでなく同期のロングテールも見る

ARC は最近/頻繁にアクセスされたデータやゴースト履歴などの情報に基づいてキャッシュ戦略を調整する。ゴーストレコードは、完全なデータをもう1つ保存するものではない。ARC のヒット率が高くても、少量の同期書き込みのロングテールレイテンシを隠蔽する可能性があるため、ワークロードごとに分離して観察する必要がある。L2ARC にはインデックス、パディング、メモリオーバーヘッドがあり、それを拡大しても、ホットスポットワークセット以外のすべてのパフォーマンス問題が自動的に解決されるわけではない。

6. 整合性チェック、scrub、resilver、バックアップ

メカニズム主に解決する問題
整合性チェック内容の不整合を検出し、正しいコピーがある場合は修復をサポートする
scrubアロケート済みデータの整合性を能動的にチェックする
resilver必要な冗長性を回復する
スナップショットと独立したバックアップ対応する履歴リカバリと障害ドメインの保護を提供する

内容が整合性チェックに合格したからといって、アプリケーションが書き込んだビジネス意味が正しいことを意味するものではなく、正常に実行された誤削除を取り消すものでもない。

ファイルシステムスナップショットはストレージ層のタイムポイントビューを提供するが、データベースのメモリ状態を外部システムと同時にコミットするものではない。アプリケーション一貫性のあるリカバリポイントは、データベースバックアップインターフェース、チェックポイント、または明示的な調整プロトコルを必要とする。

send/receive はスナップショット状態または差分を転送し、別のプールまたは別のホストのコピーを構築できる。インクリメンタルチェーンには、一致するベースと保持ポリシーが必要である。送信ストリームを生成できるからといって、回復可能なバックアップが完了したことを意味するものではなく、受信側の可用性とリカバリプロセスは依然として検証する必要がある。

7. ARC の読み取り専用読み取り、プールへの変更なし

from pathlib import Path

path = Path("/proc/spl/kstat/zfs/arcstats")
if not path.exists():
    print("ARC 統計が公開されていません。OpenZFS が読み込まれていない可能性があります")
else:
    values = {}
    for line in path.read_text().splitlines():
        columns = line.split()
        if len(columns) == 3 and columns[2].isdigit():
            values[columns[0]] = int(columns[2])
    for name in ("size", "c", "c_min", "c_max", "hits", "misses"):
        print(name, values.get(name, "提供されていません"))
    hits, misses = values.get("hits", 0), values.get("misses", 0)
    if hits + misses:
        print("累積ヒット率:", hits / (hits + misses))

ここでは累積比率であり、指定されたワークロード時間の差分に代わるものではない。zpool status はトポロジとエラーを理解するために使用し、zpool iostat はデバイス/プールのアクティビティのために使用し、zfs get は実際の属性と継承元を確認するために使用する。トポロジ、属性、ビジネスロードと組み合わせて観測を解釈し、設定の変更が必要かどうかを決定する。