【実務・中級編】 メモリ管理とエビクションポリシー – Redis

Redisメモリの深淵:エビクション戦略がシステムの命運を分ける理由

Redisを単なる「高速なKVS」と捉えているなら、それは非常にもったいない。Redisの本質は「メモリという限られたリソースを、いかに支配下におくか」というアーキテクチャそのものにある。

大規模トラフィックを捌くプロダクトにおいて、メモリ枯渇は即座にレイテンシのスパイクやOOM(Out of Memory)によるサービス停止を招く。今日は、Redisのメモリ管理の心臓部である「エビクションポリシー(Eviction Policy)」を、実戦的な視点から解剖しよう。

—

1. maxmemoryの設計思想:まずは「守り」を固める

まず大前提として、`maxmemory`を設定していないRedisインスタンスは、本番環境において「時限爆弾」を抱えているのと同じだ。

redis.confの鉄則
maxmemory 4gb # 物理メモリの余裕を見て設定せよ
maxmemory-policy allkeys-lru # 戦略なきメモリ制限は死を招く

`maxmemory`を設定することで、Redisは「メモリが一杯になったときにどう振る舞うか」という戦略(ポリシー)を選択できるようになる。ここでの設計ミスは、システムのキャッシング戦略全体を崩壊させる。

—

2. アルゴリズムの選択:LRUか、それともLFUか?

Redisは真のLRU(Least Recently Used)を実装していない。理由は単純で、メモリ消費を抑えつつ高速に動作させるため、「近似アルゴリズム」を採用しているからだ。

LRU (Least Recently Used)

「最も長い時間アクセスされていないキー」を削除する。

  • 適したケース: 直近のデータが再利用されやすい一般的なキャッシング。
  • 弱点: 「一度だけ大量にアクセスされた古いデータ」がメモリに残り続ける可能性がある。

LFU (Least Frequently Used)

「最もアクセス頻度が低いキー」を削除する。

  • 適したケース: アクセスパターンが偏るシステム。長期間使われないデータと、短期間に爆発的に使われるデータを明確に分けたい場合。
  • 強み: 過去の履歴をスコア化するため、LRUよりも「今本当に必要なデータ」を保持する能力が高い。

現場の判断基準:
アクセスパターンが予測しづらいなら`allkeys-lru`で安定を狙え。一方で、特定のデータ群に人気が集中する(ホットキーが存在する)なら、`allkeys-lfu`の方がキャッシュヒット率が劇的に向上するはずだ。

—

3. ポリシーの使い分け:`volatile`か`allkeys`か

ここを混同しているエンジニアが非常に多い。

  • `volatile-` 系:
  • `TTL(有効期限)が設定されているキー`のみを削除対象とする。
  • 設計パターン: 永続的な設定データと、揮発性のキャッシュを同じインスタンスで混在させている場合に必須。
  • `allkeys-` 系:
  • TTLに関わらず、すべてのキーを削除対象とする。
  • 設計パターン: Redisを純粋なキャッシュ層として使い、データが消えてもDBから再構築可能な場合。こちらの方がメモリ効率は圧倒的に高い。

プロの教訓:
「キャッシュ専用のインスタンス」と「永続化したいデータ」は、可能な限り物理的(あるいは論理的)に分けるのがアーキテクチャの鉄則だ。`volatile-lru`を使わなければならない状況は、往々にして設計が複雑化している証拠でもある。

—

4. パフォーマンスの罠:エビクションの代償

メモリが限界に達したとき、Redisは書き込みリクエストのたびにエビクション処理を実行する。ここで注意すべきは「ブロッキング」だ。

  • エビクションのコスト: 削除対象を探す(`maxmemory-samples`で指定した数だけサンプリングする)作業は、メインスレッドで行われる。
  • チューニングの鍵: `maxmemory-samples`のデフォルト値は5だ。これを10に上げれば精度は上がるが、CPU負荷が増大する。精度とレイテンシ、どちらを優先するかはメトリクスを見て決定せよ。

メトリクス監視のチェックポイント
INFO memory
used_memory_human を見張り、80%を超えたら要注意
evicted_keys の増加スピードをモニタリングし、不要な削除が起きていないか確認せよ

—

まとめ:アーキテクトとしての提言

Redisのメモリ管理において、最も避けるべきは「なんとなく設定したデフォルト値」で運用することだ。

1. データ特性を分析せよ: そのデータは「頻度」が重要か、「鮮度」が重要か?
2. ポリシーを固定せよ: 全てのキーをキャッシュとして扱うなら`allkeys-lru`を、TTL管理を厳密に行うなら`volatile-ttl`も選択肢に入れろ。
3. 監視を怠るな: `evicted_keys`が急増しているインスタンスは、メモリサイズ不足の警告だ。スケールアップ、あるいはシャード化(Redis Cluster)を検討するタイミングである。

Redisは非常に寛容だが、その寛容さに甘えていると、ある日突然、システムは応答を止める。メモリの挙動を完全に掌握してこそ、初めて「真のRedisエンジニア」と名乗れるのだ。

次のコードレビューでは、この視点を持ってチームの設計を問い直してほしい。それが君のシステムを堅牢にする最初の一歩だ。

コメント

タイトルとURLをコピーしました