キャッシュ戦略の基本的なパターンについて

システムアーキテクチャ

Webアプリケーションや分散システムでパフォーマンスを高めるために不可欠なのが「キャッシュ」の基本的な活用パターンについて書く。

  • キャッシュアサイド(Cache Aside)
  • リードスルー(Read Through)
  • ライトスルー(Write Through)
  • ライトバック(Write Back)
  • ライトアラウンド(Write Around)

キャッシュアサイド(Cache Aside)

概要

アプリケーション側が必要に応じてキャッシュを明示的に操作するパターンである。

graph TD
    A[アプリケーション] -->|読み込み要求| B[キャッシュ]
    B -->|ヒット| A
    B -->|ミス| C[データベース]
    C -->|データ取得| A
    A -->|キャッシュに保存| B

    A -->|書き込み| C
    A -->|キャッシュ無効化| B
sequenceDiagram
    participant A as アプリケーション
    participant C as キャッシュ
    participant D as データベース

    Note over A,D: 読み込み処理(キャッシュミス)
    A->>C: データ要求
    C->>A: キャッシュミス
    A->>D: データ取得
    D->>A: データ返却
    A->>C: データをキャッシュに保存

    Note over A,D: 書き込み処理
    A->>D: データ更新
    D->>A: 更新完了
    A->>C: キャッシュ無効化

読み込み時の流れ

  1. キャッシュにデータがあるか確認(キャッシュヒット
  2. なければDBから取得してキャッシュに保存(キャッシュミス

書き込み時の流れ

  1. データベースを更新
  2. 必要に応じてキャッシュを削除 or 更新

特徴

  • キャッシュ管理をアプリケーションが行う
  • 読み込み頻度が高く、更新頻度が低いデータに向いている
  • キャッシュとDBの整合性はアプリ側の責任である

利用例

  • Redis、Memcached等を使ったWebアプリケーション

リードスルー(Read Through)

概要

読み込み時にキャッシュがDBからの取得を自動的に処理するパターンである。アプリケーションはキャッシュのみとやり取りし、キャッシュミス時の処理は透過的に行われる。

graph TD
    A[アプリケーション] -->|読み込み要求| B[キャッシュ]
    B -->|ヒット| A
    B -->|ミス時自動取得| C[データベース]
    C -->|データ返却| B
    B -->|自動保存後返却| A

    A -->|書き込み| C
sequenceDiagram
    participant A as アプリケーション
    participant C as キャッシュ
    participant D as データベース

    Note over A,D: 読み込み処理(キャッシュミス)
    A->>C: データ要求
    C->>D: 自動的にDB取得
    D->>C: データ返却
    C->>C: 自動キャッシュ保存
    C->>A: データ返却

    Note over A,D: 書き込み処理
    A->>D: データ更新(キャッシュバイパス)
    D->>A: 更新完了

読み込み時の流れ

  1. アプリケーションはキャッシュに読み込み要求
  2. キャッシュヒット時はそのまま返却
  3. キャッシュミス時はキャッシュ自身がDBからデータを取得し、自動的にキャッシュに保存してからアプリケーションに返却

特徴

  • キャッシュがDBアクセスを透過的に処理する
  • アプリケーションはキャッシュの存在を意識しなくて良い
  • キャッシュミス時の処理がアプリケーションから隠蔽される
  • 書き込みは通常DBに直接行う

利用例

  • ORMのL2キャッシュ機能、CDN、プロキシキャッシュ、Hibernate等

ライトスルー(Write Through)

概要

書き込み操作がまずキャッシュに行われ、同時にDBにも書き込む戦略である。

graph TD
    A[アプリケーション] -->|書き込み要求| B[キャッシュ]
    B -->|同期書き込み| C[データベース]
    C -->|完了通知| B
    B -->|完了通知| A

    A -->|読み込み要求| B
    B -->|キャッシュヒット| A
sequenceDiagram
    participant A as アプリケーション
    participant C as キャッシュ
    participant D as データベース

    Note over A,D: 書き込み処理
    A->>C: データ更新要求
    C->>D: 同期書き込み
    D->>C: 書き込み完了
    C->>A: 更新完了通知

    Note over A,D: 読み込み処理
    A->>C: データ要求
    C->>A: キャッシュヒット(データ返却)

書き込み時の流れ

  1. キャッシュを更新
  2. 同じ内容をDBにも即時反映

特徴

  • キャッシュとDBが常に整合性を保つ
  • 書き込みの遅延はやや大きい
  • 読み込みは高速かつ一貫性がある

利用例

  • 一貫性が重視されるユーザープロファイル、設定情報、マスターデータなど

ライトバック(Write Back)

概要

書き込み操作はまずキャッシュにのみ反映し、DBへの書き込みは非同期的に遅延処理される。

graph TD
    A[アプリケーション] -->|書き込み要求| B[キャッシュ]
    B -->|即座に完了通知| A
    B -->|非同期でバッチ書き込み| C[データベース]

    A -->|読み込み要求| B
    B -->|キャッシュヒット| A

    D[バックグラウンドプロセス] -->|定期的に| B
    D -->|まとめて書き込み| C
sequenceDiagram
    participant A as アプリケーション
    participant C as キャッシュ
    participant D as データベース
    participant B as バックグラウンドプロセス

    Note over A,D: 書き込み処理(非同期)
    A->>C: データ更新要求
    C->>A: 即座に完了通知

    Note over A,D: 読み込み処理
    A->>C: データ要求
    C->>A: キャッシュヒット(データ返却)

    Note over A,D: バックグラウンド同期
    B->>C: ダーティデータ確認
    C->>B: 未同期データ返却
    B->>D: バッチ書き込み
    D->>B: 書き込み完了

書き込み時の流れ

  1. キャッシュにのみ書き込み(ダーティマーク付与)
  2. アプリケーションには即座に完了を通知
  3. 後でバッチ or イベント駆動でDBを更新

特徴

  • 書き込みが高速(低レイテンシ)
  • クラッシュ時にデータ消失のリスクがある
  • 高頻度な更新に向く(同じキーへの連続更新が最終結果だけで済む)
  • ダーティデータの管理が重要

利用例

  • CPUキャッシュ、ログ、ゲームの一時スコア、計測データなど

ライトアラウンド(Write Around)

概要

書き込み操作をキャッシュに反映せず、DBのみに書き込む戦略である。

graph TD
    A[アプリケーション] -->|書き込み要求| C[データベース]
    C -->|完了通知| A

    A -->|読み込み要求| B[キャッシュ]
    B -->|ミス| C
    C -->|データ取得| B
    B -->|キャッシュに保存後返却| A

    B -.->|キャッシュをバイパス| X[書き込み時はスキップ]
sequenceDiagram
    participant A as アプリケーション
    participant C as キャッシュ
    participant D as データベース

    Note over A,D: 書き込み処理(キャッシュバイパス)
    A->>D: データ更新(キャッシュスキップ)
    D->>A: 更新完了

    Note over A,D: 読み込み処理(キャッシュミス)
    A->>C: データ要求
    C->>A: キャッシュミス
    A->>D: データ取得
    D->>A: データ返却
    A->>C: データをキャッシュに保存

書き込み時の流れ

  1. キャッシュをバイパスしてDBへ直接書き込み

読み込み時の流れ

  • 読み込み時にキャッシュミスが発生 → DBから読み出してキャッシュに保存

特徴

  • 書き込みがキャッシュを汚染しない(不要なデータをキャッシュに載せない)
  • 書いた直後の読み込みでミスが起きやすい(キャッシュに存在しないため)

利用例

  • アクセスログ、一時ファイル、バックアップデータなど(低頻度アクセスのレコード)

各パターンの比較表

戦略 概要 読み込み高速 書き込み高速 整合性 キャッシュ管理
キャッシュアサイド アプリが明示的にキャッシュ操作 △(管理必要) △(手動) アプリが管理
リードスルー キャッシュが透過的にDB取得 △(DBに直接) △(読み込み時のみ) 自動(読み込み)
ライトスルー キャッシュとDBに同時書き込み △(同期待機) ◎(常に同期) 自動
ライトバック キャッシュのみ書き込み後で同期 ◎(非同期) △(遅延同期) 自動(リスクあり)
ライトアラウンド 書き込み時はキャッシュバイパス ◎(DB直接) △(読み込みで整合) 自動

まとめ

どの戦略がベストかは、ユースケースとトレードオフによる。

  • 読み込みが主で整合性も重視 → ライトスルー
  • 読み込みの透過性を重視 → リードスルー
  • 書き込み性能最重視、若干のデータ消失リスクOK → ライトバック
  • 低頻度アクセス、キャッシュ効率重視 → ライトアラウンド
  • 細かい制御が必要、開発工数をかけられる → キャッシュアサイド

選択時は以下の要素を考慮する:

  • 整合性要件: 強整合性が必要かどうか
  • 性能要件: 読み込み/書き込みのどちらを重視するか
  • 可用性要件: データ消失リスクの許容度
  • 運用コスト: 管理の複雑さと開発工数

キャッシュ戦略をうまく使いこなすことで、アプリケーションの性能と可用性は大きく向上する。各プロジェクトの要件に合った選択が重要である。