3秒でわかる
一度得た結果を手近な場所に取っておき、次回は計算や通信を省いて返す仕組み。速度を上げ、重い処理や外部への負荷を減らすために使います。
もう少し詳しく
どういうものか
キャッシュは、時間のかかる処理の結果を手近な場所に控えておき、同じ要求が来たときに元の処理をやり直さずに返す仕組みです。元のデータがある場所を配信元、控えを持っている側をキャッシュと呼びます。速さのために正しさを少し犠牲にする取引だと考えると、性質がつかみやすくなります。
キャッシュは階層のあちこちに置かれます。CPU のレベル 1 キャッシュ、OS のページキャッシュ、データベースのバッファプール、アプリ内のメモリ、Redis のような外部のキャッシュサーバー、ブラウザのキャッシュ、CDN のエッジと、同じ考え方が層を変えて何度も現れます。
なぜ必要か
同じ商品一覧を 1 秒間に千回表示するサイトで、毎回データベースに同じ問い合わせを投げるのは無駄です。結果を 30 秒だけ控えておけば、問い合わせは千回から数回に減り、応答時間も短くなります。外部 API のように呼び出し回数に料金や上限がある相手では、費用の削減にも直結します。
具体例
辞書に控えておく、いちばん素朴な形です。
_cache = {}
def get_user(user_id):
if user_id in _cache:
return _cache[user_id]
user = db.fetch_user(user_id) # 遅い処理
_cache[user_id] = user
return userつまずきやすいところ
いちばん厄介なのは、元のデータが変わったのに控えが古いままになる状態です。管理画面で価格を直したのに一覧に反映されない、という不具合の多くはこれが原因です。対策は、時間で自動的に捨てる方法と、更新した側が明示的に消す方法の 2 つがあり、多くの現場では両方を併用します。
もうひとつ、控えを持ちすぎてメモリを食い潰す事故もあります。上のコードは一度入れた分を消さないので、利用者が増えるほどメモリが増え続けます。件数の上限を決め、古いものから捨てる仕組みを入れておく必要があります。
似た用語との違い
保存という点で似ていますが、データベースは消えては困る正本を持ちます。キャッシュは消えても元から作り直せる控えです。消えたら困るデータをキャッシュだけに置いてはいけません。
覚え方
冷蔵庫の作り置きに近いものです。作るのに時間はかかるが、一度作れば数日は温め直すだけで出せます。ただし日が経てば中身は古くなり、いつ捨てるかを決めておかないと事故になります。控えを持つ判断は、必ず「いつ捨てるか」とセットで決めてください。速さのために正しさを何秒まで諦めるか、という問いに答えられない場合、キャッシュはまだ入れないほうが安全です。