ジャーナリングファイルシステムの内部(ext4/XFS)
クラッシュしてもファイルシステムが壊れない理由を、ext4のジャーナルとエクステント、XFSのB+TreeとAllocation Groupの内部構造から正確に理解できます。
- 1.ext4のジャーナル(JBD2)は更新を先にログへ書き、コミットレコードで境界を確定してから本番領域へ反映する。
- 2.ext4のdata=ordered/writeback/journalはデータブロックとメタデータの書き込み順序の保証範囲が異なる。
- 3.XFSはAllocation Group単位でB+Treeを並列管理し、ext4はエクステントツリーで連続領域をまとめて表現する。
なぜジャーナルが要るのか:更新の非原子性
ファイルへの1回の書き込みは、ディスク上では 複数の独立した更新 に分解されます。たとえばファイルへの追記は、データブロックの書き込み、inode のサイズ・タイムスタンプ更新、ブロックビットマップ(空き領域管理)の更新、場合によってはエクステントツリーのノード分割を伴います。
ディスクはこれらをまとめて原子的に書く手段を持ちません。途中で電源が落ちれば、「inode はサイズを更新済みなのに、そのブロックはまだ空きビットマップ上で空きのまま」といった 相互に矛盾した状態 が残ります。これは単なるデータ欠損ではなく、後で別ファイルがそのブロックを割り当てて二重使用する、といった連鎖的破損につながります。
古典的な対策は再起動時の fsck による全走査でしたが、TB級では数時間かかります。ジャーナリング は「これからこう書く」という計画を専用領域に先に記録し、復旧時はそのログだけを見て一貫状態へ戻す手法です。これは Write-Ahead Logging(WAL、先行書き込みログ)そのもので、DBのトランザクションログと原理を共有します。
ext4のジャーナル機構:JBD2とコミットの原子性
ext4 のジャーナルは JBD2 という独立レイヤーが担います。更新は トランザクション という単位にまとめられ、次の順序で進みます。
1. 更新対象のブロック群をジャーナル領域へ書く(descriptor + データ)
2. ストレージのバリア(FLUSH/FUA)で 1 の永続化を待つ
3. コミットレコードを書き、トランザクション完了を確定する
4. しばらく後、ジャーナルの内容を本番位置へ書き戻す(checkpoint)
5. 反映済みトランザクションをジャーナルから解放する
クラッシュ整合性の鍵は 手順2と3の順序 です。コミットレコードより前にすべての更新が永続化されていることをバリアで保証してからコミットを書くため、再起動時には次の二者択一だけが起こります。
- コミットレコードがある → そのトランザクションは完全。本番へ 再適用(redo) する
- コミットレコードがない → 不完全とみなし 丸ごと破棄 する
中途半端な「半分だけ適用された」状態が原理的に発生しないため、fsck の全走査は不要になり、ログの再生だけで一貫性が回復します。
JBD2 はコミット済みの内容を前方へ再生するだけで、DBのような undo(取り消し)は行いません。未コミットのトランザクションは「なかったこと」として捨てるだけなので、巻き戻すべき状態がそもそも残らない設計です。
3つのジャーナルモード:何を守り、何を守らないか
ext4 は data= マウントオプションで データブロックまでジャーナルに含めるか、含めない場合の 書き込み順序 を選べます。守る範囲と性能のトレードオフが本質です。
| モード | ジャーナルに書く対象 | クラッシュ後に起こり得ること |
|---|---|---|
| journal | メタデータ+データの両方 | 最も安全。全更新がログ経由なので中身も一貫。書き込み2回分で最も遅い |
| ordered(既定) | メタデータのみ。ただしデータを先に書く | メタデータは一貫。古いファイルへの新データ書き込みは保護されるが、追記中の末尾は失われ得る |
| writeback | メタデータのみ。順序は保証しない | メタデータは一貫だが、新inodeが未書き込みデータ領域を指し、旧データ(ゴミ)が見えることがある |
既定の ordered が要点です。これは「メタデータをコミットする前に、対応するデータブロックを本番位置へ書き終える」順序制約だけを課します。データ自体はジャーナルを通らないため2重書き込みを避けつつ、「inode が指すブロックには必ず正しいデータが入っている」ことを保証します。
ordered でも writeback でも、守られるのは ファイルシステム構造の整合性 であって、アプリが書きかけだったデータの永続性ではありません。「FS は壊れていないが、直前に追記した内容は消えた」は正常な挙動です。確実に残すには システムコール の fsync を呼び、コミットの完了を明示的に待つ必要があります。
エクステントツリー:連続領域をまとめて持つ
ext3 までは1ブロックごとに位置を記録する間接ブロック方式で、1GBのファイルが数十万エントリを要しました。ext4 は エクステント(連続ブロックを「開始+長さ」で表す範囲)を導入し、最大128MBの連続領域を1エントリで表します。
エクステントは inode 内に埋め込まれた B+Treeに似た木構造(エクステントツリー)で管理されます。inode には4エントリ分の領域があり、断片化が少なければ木を作らずここに収まります。足りなくなると、葉に実エクステント、内部ノードにインデックスを置く木へ拡張されます。
ファイル論理ブロック → 物理ブロックの対応(エクステント)
[ logical 0, len 1000, phys 50000 ] ← 連続1000ブロックを1エントリ
[ logical 1000, len 500, phys 80000 ] ← 別の連続領域
連続領域を1エントリで表せるため、メタデータが激減し、シーケンシャル読み出しのプリフェッチも効きやすくなります。割り当て時は 遅延アロケーション(delayed allocation)を併用し、書き込みをページキャッシュに溜めてから物理位置をまとめて決めることで連続性を高めます。これは メモリマップトファイル と同じくページキャッシュ上で更新を集約する発想です。
XFSの設計:Allocation GroupとB+Tree
XFS は大容量・高並列を前提に設計されたファイルシステムで、構造の中心が Allocation Group(AG) です。ボリュームを複数のAGに分割し、各AGが自分専用の空き領域管理・inode管理を 独立して 持ちます。
XFSボリューム
├─ AG0 : 空きエクステントB+Tree(2本)+ inode B+Tree
├─ AG1 : 〃 ← 別CPUから並列に割り当て可能
└─ AG2 : 〃
AGごとに管理構造が分かれているため、複数CPUが別々のAGに対して ロック競合なく並列に 割り当てを実行できます。これがXFSのスケーラビリティの源です。各AGは空き領域を2本のB+Treeで持ち、一方は 開始ブロック順、もう一方は サイズ順 にソートします。前者は隣接領域の結合判定、後者は「指定サイズ以上の空きを探す」最適合わせ探索を高速化します。
XFS の inode 数は固定ではなく動的に増え、ディレクトリやエクステントマップも大規模化すると専用のB+Treeで管理されます。木の各ノードはディスクブロックに対応し、探索計算量は O(log n) に抑えられます。
XFS はメタデータのみをジャーナリングし、ext4 の data=journal に当たるモードを持ちません。代わりに 非同期な論理ロギング(変更された差分だけを記録)を採用し、同じメタデータが連続更新されてもジャーナル書き込みを集約します。データの一貫性は コピーオンライト を使う Btrfs/ZFS とは異なるアプローチで、XFS はあくまで構造の整合性に責務を絞ります。
クラッシュ整合性の本質:バリアと順序
ジャーナリングが機能する前提は、ストレージへの書き込み順序が守られること です。現代のディスクやSSDは内部に揮発キャッシュを持ち、OSが出した順とは違う順で永続化することがあります。これを放置すると、コミットレコードがデータ本体より先に永続化され、ジャーナルの原子性が崩れます。
そこでFSは FLUSHコマンド(キャッシュ全体の永続化)と FUA(Force Unit Access、その書き込みだけ確実に永続化) をコミット前後に発行し、ハードウェア層に順序を強制します。ext4 の barrier=1(既定)はこれを有効にする設定です。
性能目的で barrier=0 にしたり、ストレージのライトキャッシュを有効にしたまま電源保護(バッテリ/キャパシタ)がない構成だと、ジャーナルの順序保証が崩れ、クラッシュ時にFSが破損し得ます。ジャーナリングは「バリアが正しく効いている」前提の上に成り立つ保証である点を忘れてはいけません。
まとめ
- ジャーナリングは WAL(先行書き込みログ) であり、更新を先にログ化しコミットレコードで境界を確定することで、復旧を redo の再生だけに単純化する。
- ext4 の
data=モードは 守る範囲が違う。ordered(既定)はメタデータの整合性とデータ先行書き込みを保証するが、ファイルの中身の永続性はfsyncに委ねられる。 - ext4 の エクステントツリー は連続領域を範囲で表してメタデータを削減し、XFS の Allocation Group+B+Tree はAG単位の独立管理で高い並列性を得る。
- すべての保証は バリア(FLUSH/FUA)による書き込み順序 が土台であり、これが崩れるとジャーナルの原子性自体が破綻する。基礎は ファイルシステム も参照してください。
OS Article
ジャーナリングファイルシステムの内部(ext4/XFS)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ファイルシステム
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 5
導入後に効く点
ext4のdata=ordered/writeback/journalはデータブロックとメタデータの書き込み順序の保証範囲が異なる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 5
判断チェックリスト
- 自社の用途が「ファイルシステム / ext4」に近いか確認する。
- 強みである「ext4のジャーナル(JBD2)は更新を先にログへ書き、コミットレコードで境界を確定してから本番領域へ反映する。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。