概要
キャッシュにおけるアーキテクチャパターンをまとめておきます。
表形式にすると次のようになります。
| パターン | 読み取り速度 | 書き込み速度 | データ整合性 | 主な用途 |
|---|---|---|---|---|
| Cache Aside | 高 | 中 (キャッシュ層がオーバーヘッドにならない) |
中 (期限切れ考慮) |
一般的なWebアプリ |
| Read-Through | 高 | 中 (同上) |
高 | 読み取り専用が多いデータ |
| Write-Through | 最高 | 低 | 最高 | 整合性が重要なデータ |
| Write-Around | 中 | 高 | 中 | 大量のログ書き込み等 |
| Write-Back | 最高 | 最高 | 低 | 書き込み頻度が極端に高い |
取得パターン
まずは取得系のパターンです。
Cache Aside
よくあるパターンです。Look Aside や Read Aside とも呼ばれます。

メリット
- 読み取りの多いワークロードに最適
- ロジックがシンプル
- キャッシュコンポーネントで障害が起きても問題ない
デメリット
- 呼び出し側がキャッシュを意識しないといけない
- 初回アクセス時は必ずキャッシュミスが発生する(コールドスタート問題)
- 初期は暖気しておいた方が安全。
- データ整合性がずれることがある
- TTLでなるべく最新になりやすいよう管理が必要
Read-Through
アプリケーションが常にキャッシュだけを読み取るパターンです。
ただもちろんキャッシュの内部的にはDB読み込みが発生することもあります。

メリット
- Cache Asideに似ているが、参照が透過的になっている(=アプリケーション側がDBを意識しなくて済む)
- ライブラリで吸収することが多い
- 同じデータが何度も要求されるような読み込みの多いワークロードに最適
- 例)ニュース記事
デメリット
- キャッシュプロバイダー側でDB接続ロジックを実装する必要がある
- コールドスタート問題がある。初期は暖気しておいた方が安全。
- キャッシュレイヤの障害に弱い(実装次第だが)
更新パターン
次はキャッシュの更新パターンです。
Write-Through
アプリケーションがデータをキャッシュ→DBと両方に書き込むパターンです。

良く見る図は上のように透過的にされてますが、SDKなどで対応していない限りは下のように愚直に実装するパターンが多いです。

メリット
- データ整合性が高い
- DynamoDB Acceleratorは、リードスルー/ライトスルーキャッシュの良い例
デメリット
- 両方書き込むため、書き込み速度が遅くなる
- 書き込みがヘビーな要件でボトルネックになる可能性がある
- 書き込んだが使われないデータでキャッシュ容量が無駄になる
Write Around
書き込み時はDBにのみ直接保存し、キャッシュには何もしないパターンです。
Cache Asideと併用する形になります。普通に作るとこれになります。

メリット
- Write-Throughにある「一度書き込まれたが、その後しばらく読み込まれないデータ」でキャッシュが無駄に増えることがない
- 読み込みが少ないユースケースに適している
デメリット
- 書き込んだ直後の読み取りで必ずキャッシュミスが発生
Write-Back
基本キャッシュに書き込み、一定時間経過したり一定量溜まったら非同期でDBに書き込むパターンです。

メリット
- Writeヘビーなユースケースに適している
- DBへの書き込み・負荷を低減できる
- DBが落ちてもキャッシュデータを使える
デメリット
- データロストの可能性がある
- DBに書き込む前にキャッシュが落ちた場合
- 更新がリアルタイムでないためデータ整合性が低い
まとめ
キャッシュにおける主要な標準パターンをまとめました。