SDN
← 演習一覧へ

検索エンジン用のクエリキャッシュ(LRU)を設計せよ

課題

検索エンジンの前段に置く、直近のクエリ結果を保存するキャッシュを設計する。検索リクエストが来たら、同じクエリの結果がキャッシュにあれば(cache hit)即返し、無ければ(cache miss)裏のサービスから取得してキャッシュに保存する。メモリは有限なので、古いエントリを賢く捨てる必要がある。高可用が必須。『LRU(最近最も使われていないものから捨てる)をどんなデータ構造で実装するか』が核心です。

制約・前提
  • 人気クエリはほぼ常にキャッシュに乗っている状態にしたい
  • expire/refresh(いつ捨てる・更新するか)の方式を決める必要がある
  • 高速lookup・低いマシン間レイテンシ・限られたメモリ
  • ユーザーは10M(1000万)人
  • クエリは10B(100億)/月
  • 1検索あたり270 bytes、全部ユニークなら2.7 TB/月
  • 平均4,000 req/s、高可用が必須
主要数値
概算(back-of-the-envelope)の出発点。
平均req/s4,000 req/s
クエリ数10B (100億)/月
1検索のサイズ270 bytes
全ユニーク時の月間データ量2.7 TB/月
LRUの計算量lookup/更新/削除すべて O(1)
LRUの実装doubly-linked list + hash table
主要数値の可視化

リクエスト量と月間データ量

read

全ユニーク時の月間データ量

read-heavy (4,000 req/s) LRU(doubly-linked list + hash table)でlookup/更新/削除すべてO(1)。ホットなクエリをメモリに保持。

まず自分で設計を考えてから、1ステップずつ答え合わせをしましょう。

Step 1: 要件・ユースケース(まだ伏せられています)

考えてみよう(面接官の追加質問)
  • LRUの代わりにLFU(Least Frequently Used)を使うとどう変わる? どんなアクセスパターンでLFUが有利か?
  • 『1回だけ大量に来るが二度と来ないクエリ』がLRUを汚す問題(cache pollution)をどう防ぐ?
  • 分散キャッシュであるノードが落ちたら、そのノードが持っていたエントリはどうなる? 影響を最小化するには?
  • 検索結果の元データが更新されたとき、該当キャッシュをどうやって無効化(invalidate)する?
  • TTLとLRUを併用する場合、それぞれが何の問題(古さ vs 容量)を解決しているか説明できるか?