はじめに (対象読者・この記事でわかること)

本記事は、Linux のファイルシステムに関心があるシステム管理者や開発者、特に ext3 の内部動作を深く理解したい方を対象としています。ext3 がデータやメタデータをディスクに書き込むタイミングや周期、ジャーナリングがどのようにスケジュールされるかを具体的に解説し、パフォーマンスチューニングや障害復旧時の判断材料を提供します。記事を書くきっかけは、実務で ext3 の書き込み遅延が原因でバックアップが失敗した経験から、正しい知識を共有したいと考えたことです。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • 基本的な Linux コマンド操作 (ls, mount, tune2fs など)
  • ファイルシステムの概念 (inode, ブロック, ディレクトリ構造)
  • Unix 系 OS のジャーナリング概念の概要

ext3 の書き込みメカニズムと背景

ext3 は、ext2 にジャーナリング機能を追加した Linux 標準のジャーナルファイルシステムです。ジャーナリングは、システムクラッシュ時にメタデータの整合性を保つために、変更内容を「ジャーナル」と呼ばれる領域に先に書き込み、後で実際のデータ領域に反映させる二段階コミット方式を採用しています。

ジャーナルの構造と役割

ジャーナルはスーパーブロック、ジャーナルヘッダ、エントリ、データブロックの四つの構成要素から成り、主に以下の三つのモードで動作します。

  1. writeback: メタデータのみを書き込み、データは非同期でディスクへ。
  2. ordered (デフォルト): メタデータを書き込む前に対象データを書き込み完了させる。
  3. journal: データとメタデータの両方をジャーナルに記録し、後で対象領域に反映。

このモード選択により、ディスクへの実際の書き込みタイミングが大きく変わります。特に ordered モードでは、データブロックの書き込み完了を保証した上でメタデータを書き込むため、書き込みの順序制御が重要です。

スーパーブロックとバイトマップ更新

ext3 では、スーパーブロックやブロックビットマップ、inode ビットマップといったメタデータもジャーナル対象です。これらはファイルやディレクトリの作成・削除時に頻繁に更新され、ジャーナルがフラッシュされるタイミングでディスクへ永続化されます。スーパーブロックは 1 秒ごとにバックアップスーパーブロックが更新される設定が標準で、障害復旧時に利用されます。

ディスクへの書き込みタイミングと周期の詳細

ext3 がディスクへ書き込むタイミングは、ジャーナルのフラッシュ、inode の更新、ブロックビットマップの更新、データブロックの書き込みの四つに大別できます。以下では、各プロセスがどのようなスケジュールで走るか、実際のカーネルパラメータ例とともに解説します。

1. ジャーナルのフラッシュ周期

ジャーナルはカーネルパラメータ commit= によってフラッシュ間隔を制御します。デフォルトは 5 秒です。この値は /proc/sys/fs/ext3/commit_interval (または tune2fs -c) で確認・変更できます。

  • commit=5(デフォルト): 5 秒ごとにジャーナル全体をディスクへ書き込み。
  • commit=0: 同期書き込み(データの安全性は最大、性能は低下)。
  • commit>5: 書き込み負荷が低い環境でパフォーマンス向上。

ジャーナルがフラッシュされると、ジャーナル内の全エントリがディスクのジャーナル領域に書き込まれ、続いてデータ領域への反映(replay)が行われます。

実装例

Bash
# 現在の commit interval を確認 cat /proc/fs/ext3/commit_interval # 10 秒に変更(永続化は /etc/sysctl.conf へ追加) echo 10000 > /proc/fs/ext3/commit_interval

2. データブロックの書き込みタイミング

データブロックは ordered モード時に、writeback モード時は非同期でスケジュールされます。カーネルはページキャッシュに保持された「dirty page」を一定の条件でディスクに書き出します。この条件は dirty_expire_centisecsdirty_writeback_centisecs によって制御されます。

パラメータ デフォルト 説明
dirty_expire_centisecs 3000 (30s) dirty ページが「期限切れ」と見なされ、強制的に書き込み対象になるまでの時間
dirty_writeback_centisecs 500 (5s) バックグラウンドの書き込みスレッドがページを書き込み始める時間

例: 5 秒ごとにバックグラウンドスレッドがページを書き込み、30 秒経過したページは強制的に書き込み対象となります。これにより、ディスクへの I/O が一定のリズムで発生し、突発的なスパイクを抑制できます。

実装例

Bash
# 現在の設定を確認 sysctl vm.dirty_expire_centisecs sysctl vm.dirty_writeback_centisecs # 10 秒に緩和(データ保護が緩くなるが性能向上) sysctl -w vm.dirty_expire_centisecs=10000 sysctl -w vm.dirty_writeback_centisecs=2000

3. inode とビットマップの更新周期

inode やビットマップはジャーナルのフラッシュと同時にディスクに書き込まれますが、delayed allocation(遅延割り当て)という機構が有効になると、実際のブロック割り当てもジャーナルフラッシュまで遅延します。/proc/sys/fs/ext3/delayed_allocation が 1 の場合、ブロック割り当ては「書き込み」時点ではなく、データがジャーナルに確定した時点で実行されます。

  • 利点: 小さな書き込みをまとめて大きなシーケンシャル I/O に変換でき、ディスク効率が向上。
  • 欠点: クラッシュ時に割り当てが失われるリスクが増える(ただしジャーナルが保証する)。

設定例

Bash
# 遅延割り当てを有効化 echo 1 > /proc/sys/fs/ext3/delayed_allocation # 無効化(即時割り当て) echo 0 > /proc/sys/fs/ext3/delayed_allocation

4. スーパーブロックのバックアップ周期

ext3 は複数のスーパーブロックをディスク上に保持し、mkfs.ext3 時に間隔を指定できます。バックアップスーパーブロックは 5% のブロックごとに配置されるのが一般的です。dumpe2fs -h /dev/sdX1 で確認できます。バックアップはジャーナルフラッシュとは独立して書き込まれ、クラッシュ後のリカバリ時に使用されます。

確認例

Bash
# スーパーブロック情報を表示 dumpe2fs -h /dev/sda2 | grep "Backup superblock"

ステップごとの総合フロー

以下に典型的な書き込みシナリオを時系列で示します。

  1. アプリケーションがデータを書き込む → ページキャッシュに dirty page が生成。
  2. dirty page が期限切れもしくはバックグラウンドスレッドにより flush → データブロックがジャーナルへ書き込まれる(ordered/ writeback に応じて順序が決定)。
  3. ジャーナルフラッシュタイマ (commit=5) が満了 → ジャーナル全体がディスクに永続化。
  4. ジャーナル replay が完了 → データブロックとメタデータ(inode, ビットマップ)が本来の位置へ反映。
  5. スーパーブロックのバックアップ更新 (一定間隔で自動実行)。

このフローが繰り返されるため、ext3 のディスク書き込みは 数秒単位の周期ページキャッシュの状態 に左右されます。

ハマった点やエラー解決

問題 1: commit_interval がデフォルトの 5 秒より長くなると、クラッシュ時にジャーナルが失われる

  • 症状: システムクラッシュ後、マウント時に「Journal has aborted」エラーが出る。
  • 解決策: /etc/fstabdata=orderedcommit=5 を明示的に指定し、tune2fs -c 0 -i 0 でジャーナルサイズを最適化。

問題 2: dirty_writeback_centisecs が過度に短く設定され、ディスク I/O が頻繁になる

  • 症状: iostat で write IOPS が急増し、CPU 使用率も上がる。
  • 解決策: sysctl -w vm.dirty_writeback_centisecs=2000(20 秒)に緩和し、vm.dirty_background_ratio を 5% に設定してバックグラウンド書き込み量を抑える。

問題 3: delayed_allocation を無効化した結果、ファイル単位で小さな書き込みが大量に発生

  • 症状: 大量の小ファイル書き込みでディスクシークが頻発し、パフォーマンスが低下。
  • 解決策: delayed_allocation を再度有効化し、必要に応じてアプリ側で fsync 呼び出しを最小限に抑える。

まとめ

本記事では、ext3 ファイルシステムにおけるディスク書き込みのタイミングと周期について、ジャーナルフラッシュ、dirtyページの書き出し、遅延割り当て、スーパーブロックバックアップという四つの視点から体系的に解説しました。

  • ジャーナルフラッシュは commit= パラメータで制御し、デフォルトは 5 秒。
  • dirty ページは dirty_expire_centisecsdirty_writeback_centisecs により数秒単位でディスクへ書き出される。
  • 遅延割り当て (delayed allocation) が有効な場合、ブロック割り当てもジャーナルと同調して遅延する。
  • スーパーブロックは一定ブロック間隔でバックアップが作られ、障害復旧時の鍵となる。

これらの知見を活かすことで、ext3 環境でのパフォーマンスチューニングや障害時の復旧判断が迅速に行えるようになります。次回は、ext4 と比較した際の書き込み最適化手法や、最新のファイルシステム(btrfs, XFS)での類似メカニズムについても取り上げる予定です。

参考資料