ふくふくHukuhuku Inc.
EP.06Performance 14分公開: 2026-09-20

キャッシュ戦略の選び方 ── 本体は「いつ捨てるか」の設計

キャッシュは速度と引き換えに整合性のリスクを買う仕組みです。どの層に置くかより、いつ捨てるかのほうが難しい。層ごとの性質と、無効化の方式を整理します。

#パフォーマンス#キャッシュ#設計#アーキテクチャ
執筆 / 監修
松尾 亮合同会社ふくふく 代表社員

データ基盤・データパイプライン構築 / BI / 生成 AI 活用支援を専門とするエンジニア (28 年)。 本記事は AI 利用ポリシーに基づき、生成 AI の補助で執筆 → 人間が監修・編集して公開しています。

プロフィール詳細
シェア

は、一度得た結果を手元に取っておき、次回はそれを返す仕組みです。効果は大きく、桁で速くなることも珍しくありません。

同時に、元のデータと食い違う可能性を買うことになります。導入で難しいのは保存する側ではなく、いつ捨てるかの設計です。この回はそこを中心に扱います。

1. 入れる前に確認すること

キャッシュは強力なので、本来やるべき改善を覆い隠します。入れる前に確認する項目があります。

  • そもそも処理が無駄に重くないか — EP.3〜5 の改善で足りるなら、そちらが先
  • 同じ問い合わせが本当に繰り返されているか — 毎回違う条件なら効かない
  • 古い情報を返してよいか — ここが No なら設計が一段難しくなる
  • 食い違ったときに誰が困るか — 表示だけか、判断や金額に影響するか

1番目は特に重要です。遅いSQLをキャッシュで隠すと、初回アクセスや期限切れの直後だけ極端に遅い、という状態になります。しかもその遅さは平均に埋もれるため、 として現れます。根本を直さずに蓋をすると、問題が見えにくい形に変わるだけです。

キャッシュは根本原因を隠す

入れた瞬間に数字が改善するため、その先の調査が止まります。数か月後にキャッシュが効かない条件が見つかったとき、元の遅さがそのまま出てきます。根本を直せるなら直してから入れてください。

2. どの層に置くか

置ける場所は複数あります。利用者に近いほど効果が大きく、制御は難しくなります

層ごとの性質
効果捨てやすさ向く対象
利用者の端末最大最も難しい変わらない静的なもの
配信網(CDN)大きい難しい全員に同じ内容を返すもの
アプリの外部(共有)容易複数台で共有したいデータ
アプリ内(プロセス内)容易1台で完結する計算結果
データベース内自動同じクエリの繰り返し

捨てやすさの列が判断の中心です。利用者の端末に置いたものは、こちらから捨てられません。間違ったものを配ってしまうと、期限が切れるまで回収できないわけです。だから端末側には、変わらないと確信できるものだけを置きます。

実務で最初に手を付けやすいのは、アプリの外部に共有のキャッシュを置く形です。自分たちで明示的に捨てられ、複数台で共有できます。プロセス内は最も速いものの、台ごとに内容がずれるため、更新のあるデータには向きません。台数を増やすと「更新したのに古い情報が見える端末がある」という再現しにくい不具合になり、調査に時間を取られます。

3. いつ捨てるか

の方式は、実質的に3つです。

無効化の3方式
方式仕組み利点欠点
期限切れ一定時間で自動的に捨てる単純で堅いその時間は古い情報を返す
更新時に捨てる元データを変えたら明示的に消す常に最新消し忘れが起きる
更新時に書き直す元データと同時に書き換える常に最新で高速書き込み経路が複雑になる

迷ったら期限切れです。単純で、間違えても一定時間で自然に回復します。「更新時に捨てる」は正確ですが、元データを変える経路が複数あると必ず漏れます。管理画面から、バッチから、直接SQLから ── すべての経路で消す必要があり、1つ漏れると古い情報が残り続けます。

期限つきキャッシュと、命中率の計測
Python
import time

class TTLCache:    def __init__(self, ttl_sec: float):        self.ttl = ttl_sec        self.store = {}        self.hit = 0        self.miss = 0
    def get_or_set(self, key, build):        now = time.monotonic()        entry = self.store.get(key)        if entry and now - entry["at"] < self.ttl:            self.hit += 1            return entry["value"]
        self.miss += 1        value = build()        self.store[key] = {"value": value, "at": now}        return value
    @property    def hit_rate(self):        total = self.hit + self.miss        return self.hit / total if total else 0.0

命中率を必ず測れるようにしてください。キャッシュを入れたのに速くならない場合、その大半は命中していません。鍵が細かすぎる、期限が短すぎる、そもそも同じ問い合わせが来ていない ── 命中率が分かれば、どれなのか切り分けられます。

4. 鍵の設計

何を鍵にするかで、命中率と正しさの両方が決まります。細かすぎれば命中せず、粗すぎれば別人のデータを返します

  • 利用者ごとに違う内容なら、鍵に利用者を含める — 含め忘れると他人のデータが見える
  • 権限で見える範囲が変わるなら、権限も鍵に含める — 最も危険な取りこぼし
  • 表示に関係しない条件は鍵に含めない — 命中率が落ちるだけ
  • 鍵に含める要素は明示的に列挙する — 引数をそのまま鍵にすると、無関係な差で外れる
鍵の漏れは、性能ではなく事故になる

利用者や権限を鍵に含め忘れると、他人の情報が表示されます。性能改善のつもりが情報漏洩になるため、キャッシュの導入では鍵の設計をレビューの対象にしてください。ここは速さの問題ではありません。

5. 期限切れが重なる問題

運用で顕在化しやすいのが、多数のキャッシュが同時に期限切れになる現象です。同時に作り直しが始まり、元のデータベースに負荷が集中します。

起きやすいのは、一斉に作られたキャッシュが一斉に切れる場合です。再起動直後や、キャッシュを全消しした直後に発生します。対処は単純で、期限に少しばらつきを持たせることです。

期限にばらつきを持たせて、同時切れを避ける
Python
import random
BASE_TTL = 300      # 基本は5分JITTER = 0.2        # ±20% のばらつき

def ttl_with_jitter(base: float = BASE_TTL) -> float:    """期限を散らして、同時に切れるのを防ぐ。"""    return base * (1 + random.uniform(-JITTER, JITTER))

# 1000件のキャッシュを同時に作っても、切れる時刻は 240〜360 秒に散るsamples = [ttl_with_jitter() for _ in range(1000)]print(f"最短 {min(samples):.0f}秒 / 最長 {max(samples):.0f}秒")

あわせて、同じ鍵の作り直しが同時に走らないようにする制御も有効です。1件だけ作り直し、他は待つか古い値を返す。作り直しが同時多発すると、キャッシュがない状態より悪化することがあります。

6. 入れたあとに残すもの

キャッシュは時間が経つと、なぜ入っているか分からなくなる種類の仕組みです。EP.1 で書いた「払った代償を残す」が特に効く領域です。

  1. 1何を速くするために入れたか — 元の遅さの数字
  2. 2どれだけ古い情報を許容する設計か — 期限の根拠
  3. 3どの経路で捨てられるか — 更新時に消す場合、すべての経路を列挙する
  4. 4命中率の目安 — 下がったときに気づけるように

3番目を書き残さないと、新しい更新経路が追加されたときに消し忘れます。これは時間差で発生し、原因が分かりにくい種類の不具合になります。

キャッシュは、入れた直後がいちばん安全で、時間が経つほど危うくなる仕組みです。元データの構造が変わり、更新経路が増え、担当者が代わる。そのどれもがキャッシュの前提を静かに崩します。 の観点で言えば、命中率と、古い情報を返した回数が観測できる状態にしておくと、崩れ始めたことに気づけます。

ここまでのまとめ

キャッシュは速度と整合性の交換。入れる前に根本を直せないかを確認する(隠すと テールレイテンシ になる)。層は捨てやすさで選ぶ。無効化は迷ったら期限切れ。鍵に利用者と権限を含め忘れると事故になる命中率は必ず測れるようにしておく。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp