インクリメンタルキャッシュ設計(差分検出)
「結果の再利用」ではなく「仕事の省略」
[[キャッシュ戦略]] の cache-aside は、取得した結果を保存して次に使い回す仕組みでした。インクリメンタルキャッシュが解くのは別の問題です。
「前回から変わっていないものは、そもそも処理しない」
対象は、全件を舐めると重い処理です。
- 数十万ファイルのディスク走査(サイズ集計、重複検出)
- 大量の入力に対する変換([[データパイプライン・ETL]]、静的サイト生成)
- ビルドとテスト([[CI/CD]] で変更されたパッケージだけ検査する)
違いは無効化の引き金にあります。TTL は「時間が経ったから」ですが、こちらは対象が変わったからです。時間では無効化しません。
何をもって「変わった」とするか
この選択が正しさと速さのすべてを決めます。
| 判定材料 | 速さ | 見逃し |
|---|---|---|
| 更新時刻(mtime) | 速い(メタデータのみ) | 時刻を保ったまま書き換えられると見逃す |
| サイズ | 速い | 同じ長さの書き換えを見逃す |
| 内容のハッシュ | 遅い(全体を読む) | 実質的に見逃さない |
| 更新時刻 + サイズ | 速い | 両方が一致する書き換えを見逃す |
現実的な設計は段階的な判定です。
- 更新時刻とサイズが前回と同じなら、変わっていないとみなす(大半がここで終わる)
- どちらかが違うものだけ、内容のハッシュを計算する
- ハッシュも同じなら再処理しない(触られたが中身は同じ)
速い判定で候補を絞り、高い判定で確定するという構造は、[[データベースインデックス]] が索引で候補を絞ってから実データを見るのと同じ考え方です。
キャッシュキーに何を含めるか
入力が同じでも、処理する側が変われば結果は変わります。 ここを忘れると、古い結果を使い続ける不具合になります。
キーに含めるべきもの:
- 入力の識別(パスと、上の判定材料)
- 処理のバージョン(変換ロジックを変えたら全件やり直す)
- 設定・オプション(圧縮率や除外条件が変われば結果が変わる)
処理のバージョンを含めていないと、ロジックを直したのに古い結果が返り続けます。しかも「直したはずなのに変わらない」という形で現れるため、原因に辿り着くのに時間がかかります。
消えても壊れないこと
インクリメンタルキャッシュは捨てても正しく動く必要があります。
- キャッシュを消したら全件処理に戻るだけ — 結果は変わらない
- キャッシュが壊れていたら捨てる — 読めない・形式が古いときは無視して作り直す
- キャッシュに正本を置かない — キャッシュにしか無いデータがあると、それは [[バックアップとリカバリ]] の対象であってキャッシュではありません
「消しても直る」を保つことが、この設計の安全弁です。 迷ったら消せる状態にしておけば、不整合が疑われたときの切り分けが一手で済みます。
実務での注意点
- キャッシュを消す手段を用意する —
--no-cache相当のオプションが無いと、疑わしいときに検証できません - ヒット率を出す — 「何件中何件を省略したか」を出力すると、効いていないことに気づけます。効いていないキャッシュは、判定コストだけ払っています
- 保存先はやり直せる場所に — 一時ディレクトリなど、消えても構わない場所に置きます
- 並列処理と組み合わせるときは書き込みを直列に — 複数のワーカーが同じキャッシュファイルへ書くと壊れます。集約してから1回書きます
関連技術とのつながり
- [[キャッシュ戦略]] — 結果の再利用。無効化の引き金が時間か変更かで役割が分かれる
- [[バッチ処理]] — 全件処理を前提とする処理を、変更分だけに絞る手段
- [[データパイプライン・ETL]] — 増分取り込みの考え方と同じ構造
- [[CI/CD]] — 変更されたパッケージだけを検査する絞り込みに使う
- [[データベースインデックス]] — 安い判定で候補を絞り、高い判定で確定する構造が共通
Q: インクリメンタルキャッシュの無効化の引き金はどれ?
- [ ] 一定時間の経過(TTL)
- [x] 対象が変わったこと
- [ ] メモリ使用量の上限
解説: 「結果を使い回す」キャッシュとは異なり、「変わっていないものは処理しない」ための仕組みです。
Q: 変更判定を「更新時刻とサイズ」だけで行うと起きうる問題はどれ?
- [ ] 処理が遅くなる
- [x] 両方が一致する書き換えを見逃す
- [ ] キャッシュが肥大化する
解説: 速い判定で候補を絞り、差があるものだけ内容のハッシュで確定する段階的な設計が現実的です。
Q: キャッシュキーに処理のバージョンを含めないと何が起きる?
- [x] 変換ロジックを直しても古い結果が返り続ける
- [ ] キャッシュのヒット率が下がる
- [ ] キャッシュが読めなくなる
解説: 「直したはずなのに変わらない」という形で現れるため、原因に辿り着くのに時間がかかります。