99. 満杯のキャッシュは忘れることで生き延びる — maxmemoryポリシーのLRU/LFUとホットキーという偏り
キャッシュのメモリが上限に達したとき「何を忘れるか」がどう決まるのか、そしてハッシュで均しても残る2つ目の偏り=ホットキーがどこで生まれるのかを、図で追っていきます。
① 上限に達すると「忘れる」判断が始まる
- 公式の言い回し: 「Eviction occurs when the max-memory on the cluster is consumed and a policy is in place to allow eviction.」——エビクションは「上限に達した」かつ「追い出しを許すポリシーがある」ときに起きる。
- ポリシーは cluster parameter group の maxmemory-policy で管理する(公式: 「This policy can be managed using the maxmemory-policy on the cluster parameter group.」)。
- noeviction は追い出しをしないポリシー。空きが作れないので、上限到達後は新しい値が保存されず書き込みがエラーになる(=容量を守る代わりに書き込みを犠牲にする)。Valkey公式の原文: 「New values aren't saved when memory limit is reached」。
- DynamoDB編の「ストレージは無限に増えない、だからパーティションで分ける」と前提は同じ——メモリには天井があり、天井に当たったときの振る舞いを設計項目として選ぶ。
満杯のキャッシュには2つの道しかない——古いものを忘れて空きを作るか、書き込みを断るか。どちらを選ぶかは maxmemory-policy という1つのパラメータに集約されている。
② 「何を忘れるか」は対象×基準の2×2
- 既定は volatile-lru。公式の説明: 「The default policy volatile-lru frees up memory by evicting keys with a set expiration time (TTL value).」——TTL(期限)が設定されているキーの中から選ぶ。
- 公式の言い回し: 「Least frequently used (LFU) and least recently used (LRU) policies remove keys based on usage.」——lru/lfu はどちらも「使われ方」で消す。
- 8つの値は、AWS公式のパラメータグループドキュメントに maxmemory-policy の Permitted values として明記されている(Default: volatile-lru も同ページで確認)。なお lfu の2値は Redis OSS 4.0.10 で追加されたもの。
- volatile-* はTTL付きの候補が尽きて空きを作れない場合、volatile-lru / volatile-lfu / volatile-random / volatile-ttl は noeviction と同様に振る舞い、書き込みが失敗しうる(Valkey公式: 「behave like noeviction if there are no keys to evict matching the prerequisites」)。allkeys-* は全キーが候補なのでこの詰まりが起きにくい。
エビクションの設計とは「対象(volatile/allkeys)×基準(lru/lfu/random/ttl)」の格子から1マスを選ぶこと。既定の volatile-lru は「期限付きのものから、最近使っていない順に」という保守的な初期値になっている。
③ Memcachedは自動LRU / 効きはヒット率
- Memcached: 「there is a default LRU policy in place controlling evictions on each node.」——ノードごとにLRUが既定で働く(選ぶまでもなく自動)。
- 「The number of evictions on your Amazon ElastiCache cluster can be monitored using the Evictions metric on Amazon CloudWatch.」
- ヒット率(cache hits ratio)の公式定義: 「the total of key hits divided by the total hits and misses. The closer to 1 the ratio is, the more effective your cache is.」
エビクションはMemcachedでは自動、その回数は Evictions メトリクスで見える。キャッシュ全体の健全さは「ヒット率」という単一の比率に凝縮できる——可観測性編で p99 やアラームしきい値という1つの数字で系を測ったのと同じ発想。
④ ミスが多いなら4つに分類する
- 公式の言い回し(ほぼ原文): 「A key is not in the cache because it either has been evicted or deleted, has expired, or has never existed.」——evicted / deleted / expired / never existed の4つ。
- 4つのうち evicted だけが①②の容量・ポリシー設計に直結する。Evictions メトリクスが低いのにミスが多いなら、原因は残り3つ(削除・期限・未投入)側にある、と切り分けられる。
「ヒット率が低い」を漠然と眺めず、evicted/deleted/expired/never-existed の4象限に落とすと、直すべき層(容量設計なのか、TTLなのか、キャッシュ戦略なのか)が一意に決まる。
⑤ もう1つの偏り=ホットキー
- 公式: 「These data structures [lists, streams, sets, etc.] are stored in single Keys, which reside on a single node. A very large multi-dimensional key has the potential to utilize more network capacity and memory than other data types and can cause a disproportionate use of that node.」——list / stream / set のような多次元データ構造は「1キー=1ノード」に丸ごと載る。巨大キーは特に危険。
- ハッシュは「配置」を均すが、どのキーが人気になるかは均せない——これが容量の偏り(エビクション)とは別の問題である理由。
- DynamoDB編のホットパーティション(キーをハッシュで均等に分けても、特定のキーへのアクセスが集中すれば1つの区画だけが忙しくなる)の、完全な再演。
ハッシュは平均を均すが、人気は均せない。多次元データ構造は1キーがまるごと1ノードに載るため、巨大で人気なキーは単一ノードのCPUとネットワークを食い潰す。
⑥ 対策は検出・複製・往復削減の3手
- ① 「you can detect hot keys using valkey-cli --hotkeys if an LFU max-memory policy is in place.」——LFU系ポリシーが前提。
- ② 「Consider replicating hot keys across multiple nodes ... This approach requires the client to write to multiple primary nodes (the ... node itself will not provide this functionality) and to maintain a list of key names to read from, in addition to the original key name.」——複数プライマリへの書き込みも、読み先キー名リストの管理もアプリの責務。メッセージング編・レプリカで見た「読みをレプリカに散らす」原理の、クライアント主導版。
- ③ 「ElastiCache engine 7.2 for Valkey and above, and ElastiCache version 6 for Redis OSS and above, all support server-assisted client-side caching. This enables applications to wait for changes to a key before making network calls back to ElastiCache.」——キーの変更通知を待ち、変わるまでネットワーク往復をしない=ホットキーへの読みの多くをネットワークの外で吸収する。
ホットキーは「検出(--hotkeys)→複製で散らす(クライアントの責務)→往復を消す(サーバー支援キャッシュ)」の順に手当てできる。エビクションは容量の偏りへの答え、ホットキーはアクセスの偏りへの答え——どちらも「有限の速い記憶に何を残すか」というCSの古い問題が、マネージドキャッシュでは設定値とメトリクスの形で現れたものにすぎない。