こんにちは!Redisの奥深い世界へようこそ。
今日は、Redis 4.0で導入された「LFU(Least Frequently Used)アルゴリズム」について、徹底的に噛み砕いてお話ししますね。
「キャッシュのメモリがいっぱいになったとき、どうやって古いデータを消すの?」
「最近のRedisって、ただ古いだけじゃなくて『使われていない順』に賢く消せるって聞いたけど本当?」
そんな疑問を持ったあなた、大正解です。ここをクリアすれば、Redisのメモリ管理の仕組みはバッチリマスターできますよ。専門用語は極力使わず、身近な例えを交えながら、知的好奇心を刺激する旅に出発しましょう。
—
1. なぜRedisには「お片付け(メモリ管理)」が必要なのか?
Redisは、データをすべてメモリ(RAM)の上に置く超高速なデータベースです。メモリはハードディスクと違って、無限にはありません。
カフェの席を想像してみてください。席数(メモリ)には限りがありますよね。お客さんが次々とやってきて満席になったとき、ずっと居座っているけれど、もう何時間もオーダーしていない人がいたらどうしますか? お店としては、新しく来たお客さんのために、その席を空けてもらいたいわけです。
Redisも同じです。メモリがパンクしそうになったとき、「どのデータを諦めて消去するか」を決める必要があります。これを専門用語で「Eviction(エビクション:追い出し)」と呼びます。
—
2. LRUからLFUへの進化:カフェの席取り合戦に例えると?
昔のRedisは、LRU(Least Recently Used:最近使われていない順)という方法を使っていました。これは「最後にアクセスされてから一番時間が経っているもの」を消す方法です。
- LRUのイメージ: 「最後にその本を開いたのが昨日の人」よりも、「最後に開いたのが1年前の人」の本を片付ける。
これでも十分賢いのですが、問題点もありました。
例えば、「普段は全然使わないのに、朝の1時間にだけ爆発的にアクセスされるデータ」があったとします。LRUだと、「さっきの朝の1時間にアクセスされた」という事実だけで、「最近使われたデータだ!」と勘違いしてしまい、ずっとメモリに残し続けてしまうのです。
そこで登場したのが、今回主役のLFU(Least Frequently Used:アクセス頻度が最も低い順)です。
- LFUのイメージ: 「最後にいつ使ったか」ではなく、「これまでトータルで何回使われたか(人気度)」を見る。
何年も前に一度だけ開いた本よりも、毎日ボロボロになるまで読まれている本の方が残すべきですよね。LFUは、まさに「本当の人気者」を見極めるためのアルゴリズムなのです。
—
3. Redisはどうやって「使用回数」を記憶しているのか?(ここが天才的)
「じゃあ、Redisはすべてのデータに対して『何回アクセスされたか』のカウンターをずっと持っているの?」
ここでRedisのチーフアーキテクトとしての腕の見せ所ですが、実はRedisはメモリを節約するため、たった1バイト(8ビット)しかカウンターに使っていません。
8ビットで表現できる最大の数字は「255」です。
「えっ、人気のあるデータなら、すぐに100万回とかアクセスされるよ? 255回でカンストしちゃうじゃん!」と思いますよね。
ここがRedisの恐ろしいまでの変態的(褒め言葉です)な最適化技術です。Redisは、アクセスが増えれば増えるほど、カウンターの増え方を鈍くするという確率的な仕組みを使っています。
① アクセスするたびに「確率で」カウンターが増える
`lfu-log-factor` という設定で調整しますが、例えばアクセスされるたびに毎回カウンターが「+1」されるわけではありません。人気が出れば出るほど、「今回は運良くカウンターを1増やそうかな」という確率ゲームになります。これにより、1バイトという極小のスペースで、数百万回・数億回のアクセスを疑似的に表現しているのです。
② 時間とともに人気が落ちる(忘却の美学)
世の中のトレンドは移り変わります。先週大人気だったデータも、今週は誰も見向きもしないかもしれません。
そこで、`lfu-decay-time` という設定が登場します。「一定時間が経つと、カウンターの数字を勝手に少しずつ減らす(減衰させる)」という仕組みです。
- 時間の経過(lfu-decay-time): 「あ、そろそろ1時間経ったから、みんなの人気度ポイントをちょっと引いておこう」
- アクセスの頻度(lfu-log-factor): 「お、このデータはまたアクセスされたからポイントを追加しよう」
この「減らす仕組み」と「増やす仕組み」の絶妙なダンスによって、Redisは「今、本当にアツいデータ」を常に正確に把握し続けることができるのです。
—
4. 実務での設定と使い方
設定ファイル(`redis.conf`)を覗いてみましょう。このあたりのパラメータを適切にいじることで、あなたのアプリケーションの性格に合わせたメモリ管理ができるようになります。
メモリがいっぱいになったときのポリシーをLFUの「使用頻度が低い順」に設定
maxmemory-policy allkeys-lfu
【LFUのチューニング設定】
lfu-log-factor: 数字が大きいほど、アクセスが増えたときのカウンターの上がりが緩やかになります(デフォルトは10)
lfu-log-factor 10
lfu-decay-time: 何分アクセスがないとカウンターを「1」減らすか(デフォルトは1、つまり1分ごとに減衰)
lfu-decay-time 1
もし、あなたのサービスが「ニュースサイト」や「ECサイトのトレンド商品」のように、流行り廃りが激しい性質を持つなら、`lfu-decay-time`を少し短めにして、古いトレンドが速やかにメモリから消えるように調整すると非常に効果的です。
—
5. 先輩エンジニアからのまとめ
RedisのLFU実装は、「限られたメモリ(資源)の中で、人間が忘れていくように、上手にデータを忘れる」ための美しく洗練された数学的アプローチです。
ただのカウンターではなく、確率論を組み合わせて1バイトに押し込め、さらに時間の経過とともに風化させる。この裏側の仕組みを知っているだけで、トラブルシューティングの視野が劇的に広がります。
「なぜこのデータが消えたのか?」
「どうすればキャッシュヒット率を限界まで高められるのか?」
そう悩んだときは、今日お話しした「アクセス頻度のカウント」と「時間の経過による減衰」のドラマを思い出してください。
ここをクリアしたあなたなら、もうRedisのメモリ管理で迷うことはありません。自信を持って、最高プロダクトの設計に挑んでくださいね!
コメント