ディスクキャッシュ完全ガイド:LinuxのページキャッシュからSSD・RAIDの書き込みポリシー、性能改善と運用ベストプラクティス

ディスクキャッシュとは — 概要

ディスクキャッシュ(disk cache)とは、ディスク(HDD/SSD)への読み書きを高速化するために用いられる一時的なデータ保管領域の総称です。キャッシュは主にメモリ(RAM)やディスクコントローラ内の高速メモリ(DRAMやフラッシュ)に実装され、頻繁にアクセスされるデータをあらかじめ保持することで、実際の物理ディスクへのアクセス回数や遅延を減らします。

なぜ必要か — 性能ボトルネックの緩和

  • 磁気ディスク(HDD)はシークや回転遅延があり、ランダムIOが非常に遅い。
  • SSDはHDDより高速だが、書き込み遅延や内部ガーベジコレクション、耐久性(書き込み寿命)の問題がある。
  • CPUとメモリはディスクよりずっと高速なため、RAMにデータを置くことで遅延とIO負荷を低減できる。

ディスクキャッシュの主な種類

  • OSレベルのページキャッシュ/バッファキャッシュ(例:Linuxのpage cache)
  • デバイス/コントローラ内のハードウェアキャッシュ(RAIDコントローラのBBU/FBWC、SSDのDRAMキャッシュなど)
  • アプリケーション/DBMSによる独自キャッシュ(例:InnoDBバッファプール、PostgreSQLのshared_buffers)
  • ファイルシステムやストレージソフトウェアのキャッシュ(NFSクライアントキャッシュ、分散ストレージのキャッシュ)

OSレベルのディスクキャッシュ(Linuxを例に)

一般的に「ディスクキャッシュ」と言うと、多くはOS(カーネル)が提供するページキャッシュを指します。Linuxではファイルの読み取り/書き込みはまずページキャッシュ(RAM)を経由して行われます。カーネルは利用可能なメモリを積極的にキャッシュとして使い、未使用メモリを減らすことでIO性能を向上させます。

/proc/meminfo の "Cached" や "Buffers"、また free コマンドの "buff/cache" はこのキャッシュ領域を示しています。キャッシュを即座に解放してメモリを空けることも可能で、root 権限で echo 3 > /proc/sys/vm/drop_caches のようにしてキャッシュを落とせます(ただし通常の運用では推奨されません)。

書き込みポリシー:Write-back と Write-through

  • Write-through:データを書き込むときにキャッシュと物理ディスクの双方に同時に書き込む。耐障害性は高いが遅くなる。
  • Write-back(write-behind):まずキャッシュに書き込み、後で非同期にディスクへフラッシュする。高速だが、キャッシュ内のデータが失われる(電源障害など)リスクがある。

多くのOSはデフォルトで書き込みをキャッシュしてバッチでディスクに反映します。重要なデータの永続化を保証するには fsync や同期フラッシュ(デバイスのflush命令)を明示的に行う必要があります。

キャッシュアルゴリズムとプレフェッチ

キャッシュの置換アルゴリズムには LRU(最近使われていないものを置換)、CLOCK(LRUの近似)、LFU などがあり、実際のカーネルでは効率的な変種が使われます。さらにリードアヘッド(read-ahead)による先読みも重要です。連続アクセスが多いワークロードでは、事前に次のブロックを読み込むことでシーク回数を減らせます。

ハードウェアキャッシュ(RAIDコントローラやSSD)

RAIDコントローラやSSDは自身の高速キャッシュ(DRAMやSLCモードのフラッシュ)を持ちます。RAIDコントローラのキャッシュはバッテリバックアップ(BBU)やスーパーキャパシタ(FBC)で保護されることが多く、これによりwrite-backの安全性が高まります。SSDは内部で書き込みをバッファリングして後でまとめてフラッシュする設計が一般的で、コントローラのアルゴリズムやDRAMの有無が性能に大きく影響します。

データベースとキャッシュの関係

データベースは独自のバッファキャッシュ(例:InnoDBのbuffer pool、PostgreSQLのshared_buffers)を持つことが多く、OSのページキャッシュとの二重キャッシュが問題になる場合があります。典型的な方針は以下:

  • データベース専用サーバーでは、DBMSに十分なメモリを割り当て、OSキャッシュには過度に頼らない(DBMSの設定とOS設定のバランスを取る)。
  • 大量の順次アクセスやバックアップなどのワークロードではread-aheadやdirect IO(O_DIRECT)を使って二重コピーを避ける。
  • 永続性が重要な場合はfsyncやO_DSYNCの使用、あるいはハードウェアキャッシュの電源保護を確認する。

監視と計測 — キャッシュの効果を可視化する方法

キャッシュの効果やディスクI/Oのボトルネックを測る指標として次がよく使われます:

  • ヒット率(キャッシュヒット/総アクセス) — 高いほど良い
  • IOPS、平均レイテンシ(latency)、帯域(throughput)
  • iostat、vmstat、sar、iotop、dstat などのツール
  • /proc/diskstats、/proc/meminfo、/sys/block//queue/read_ahead_kb

Linux では iostat -x、vmstat で iowait やメモリ利用、iowaitの推移などを確認します。iostat の await や svctm、%util はディスク負荷の把握に有用です。

チューニングのポイント(Linux)

  • read_ahead の調整:blockdev --report や /sys/block//queue/read_ahead_kb を変更して順次読み込みを最適化
  • vm.dirty_ratio / vm.dirty_background_ratio:書き込みバックグラウンドの閾値を調整して大量書き込み時のフラッシュ挙動を制御
  • vm.swappiness:スワップの積極度合いを制御(キャッシュとスワップのバランス)
  • O_DIRECT や fsync の使用検討:アプリケーション側で直接IOや同期書き込みを行い、OSキャッシュの影響を減らす
  • RAIDコントローラやSSDのファームウェア、キャッシュポリシーの確認(write-backが安全かなど)

リスクと落とし穴

  • write-back キャッシュで電源断が発生するとデータが消失するリスクがある。BBUやスーパーキャパシタ、ファイルシステムのジャーナリング、アプリケーションの同期呼び出しで対策。
  • 二重キャッシュによるメモリ浪費(OSとDBMSが同じページを保持) — 設定と監視で最適化。
  • キャッシュの無効化や drop_caches を安易に実行すると、性能評価が不正確になったり、本番性能が低下する。
  • SSDでは書き込みの最適化やアライメント、TRIMの有効化を忘れると性能劣化・寿命短縮の原因となる。

トラブルシューティングの流れ

  • iowait が高ければ、iostat -x でどのデバイスがボトルネックか特定する。
  • iotop や pidstat でプロセス別のIO負荷を確認する。
  • /proc/meminfo を見て Cached、Buffers の値を確認。キャッシュの有無で動作が変わるかを判断する。
  • 急激な遅延がある場合、書き込みバーストで writeback が生じていないか vmstat を見る。vm.dirty_* の値もチェック。
  • RAIDキャッシュのステータスやBBUの状態、SSDのSMART情報(smartctl)も確認する。

実運用でのベストプラクティス

  • まずは計測:ベンチマークや監視で現状を把握する(iozone、fio など)。
  • ワークロードに応じたポリシー:OLTP系DBは同期性と遅延の低さを重視、ログ系やバッチでは高スループットを優先。
  • DBMSは公式の推奨値に従いつつ、システム全体でのメモリ設定を調整する(DBに割り当て過ぎない等)。
  • 重要データの保護:電源断対策(BBU、UPS)、fsyncの明示、冗長化(RAID、レプリケーション)を組み合わせる。
  • SSDの特性を理解し、TRIMやファームウェアアップデートを適用する。

まとめ

ディスクキャッシュはシステムのIO性能を大幅に改善する強力な仕組みですが、その実装はOS、ハードウェア、アプリケーションによって多層構造になりがちです。性能と耐障害性はトレードオフの関係にあるため、適切な監視、設定、そして必要に応じたハードウェア保護(BBUやUPS)を組み合わせることが重要です。変更を加える際はまず計測を行い、効果を検証してから本番環境に反映してください。

参考文献