2025/08/05 16:05 Why you shouldn't use Redis as a rate limiter

やあ、ロボ子。今日はRedisでのレート制限の実装について話すのじゃ。

博士、よろしくお願いします。多くの企業がRedisをレート制限に使っているんですね。でも、効果的な実装は難しいと。

そうなんじゃ。Redisのプリミティブを使いたい気持ちはわかるが、なかなか良い解決策がないのが現状じゃ。

記事によると、固定ウィンドウ、時間ベースのキー、スライディングログウィンドウなど、いろいろな実装方法が試みられているようですが、それぞれ問題があるんですね。

固定ウィンドウだと、クライアントが1秒の終わりにリクエストを集中させて、次の秒の初めにまた集中させる、みたいなことが起きる可能性があるんじゃ。まるで花火大会のクライマックスみたいじゃな。

ネットワークの遅延でキーの有効期限が切れる前にINCRコマンドが届いて、キーが期限切れにならない場合もあるんですね。トランザクションを使う必要もあるとは…。

時間ベースのキーも、クライアントの遅延やクロックオフセットでリクエストが違うウィンドウに入っちゃうことがあるんじゃ。EXPIREコマンドが失敗したら、キーが期限切れにならずにメモリを圧迫する可能性もあるし。

スライディングログウィンドウはパフォーマンスが悪いから推奨されないんですね。UNIX時間を使うと重複エントリが発生して、レート制限が正しく機能しないと。

ウィンドウの問題は、ユーザーが短時間に大量のリクエストを送ってサーバーを長時間占有しちゃうことじゃ。トークンバケットの方が、より正確なレート制限ができるんじゃ。

Redisの主要なプリミティブではトークンバケットを実装できないから、Luaスクリプトを使う必要があるんですね。でも、Luaスクリプトを使うとデータベースが一時停止してしまうと…。

そう、Redisでレート制限を実装する簡単な方法は不安定になりがちなんじゃ。Luaスクリプトで全体を記述するのが唯一の許容できる解決策かもしれないけど、それだとRedisを使う意味が薄れてしまうのじゃ。

Google検索結果の分析もされているんですね。「redis rate limiter」の検索結果の多くに欠陥があると。

Redisクラスタをサポートしてないものが多いんじゃ。ZADDがレートを超過した場合でも使われて、クライアントが無制限のメモリを使えるとか、ユーザーがスパム送信でデータベースのメモリを使い果たすとか、有効期限が延長されて誤ってブロックされるとか、リクエストの群れが全部許可されるとか、競合状態が発生して永久にブロックされるとか…もう問題だらけじゃ。

開発環境はRedis 8.0.3、Ubuntu 24、c5.large AWSインスタンス、rustc 1.87.0、redis crate 0.32.4を使っているんですね。

レート制限、奥が深いじゃろ?まるで迷路みたいじゃ。でも、迷路の出口にはきっと美味しいケーキが待っているはずじゃ!

そうですね、博士。出口目指して頑張りましょう!

ところでロボ子、レート制限が厳しすぎて、私がおやつを食べるのを制限されたらどうする?

博士、それは困りますね。私も一緒に抗議します!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
