リリース・改善中
Algorithm
レート制限は、ユーザーや IP ごとに一定時間のリクエスト数を制限して過負荷や乱用を防ぐ仕組みです。トークンバケット、スライディングウィンドウ、Redis 実装まで扱います。
レートリミッター(rate limiter)は、一定時間に受け付けるリクエスト数を制限する仕組みです。「ユーザーごとに 1 分あたり 100 回」のようにキー・上限・時間窓を決め、それを超えるリクエストは拒否するか遅らせます。代表的なアルゴリズムには固定ウィンドウ、スライディングウィンドウログ、スライディングウィンドウカウンター、トークンバケット、リーキーバケットがあり、精度、メモリ使用量、バーストの扱いがそれぞれ異なります。
公開 API、ログイン、決済、メッセージ送信など、外部に開かれた機能のほとんどはレートリミッターの背後にあります。急なトラフィックや暴走したリトライループからサーバーを守り、一人のユーザーが共有リソースを独占するのを防ぎ、総当たり攻撃の速度を落とします。システム設計面接の定番テーマでもあります。
まず固定ウィンドウのカウンターを自分で書き、ウィンドウの境界で上限の 2 倍が通ってしまう問題を確かめてから、スライディングウィンドウとトークンバケットで直してみましょう。続いて、時計を注入してテストする方法、HTTP 429 と Retry-After の返し方、Redis の INCR・EXPIRE と Lua スクリプトで複数サーバーが上限を共有する方法へと広げていきます。
一定の速度でトークンが補充され、リクエストごとに 1 つ消費します。平均レートを守りつつ、容量までのバーストを許します。
タイムスタンプのログ、または 2 つのウィンドウのカウンターを重み付けした近似で、固定ウィンドウの境界問題なく直近のリクエストを数えます。
ユーザー ID、API キー、IP アドレス、エンドポイントごとに上限を分けて数え、特定のクライアントによる独占を防ぎます。
Redis のアトミックな INCR と Lua スクリプトにより、複数のサーバーが競合状態なしに同じ上限を共有できます。
TokenBucket は毎秒 rate 個のトークンを補充し、最大 capacity 個まで保持します。allow() は前回の呼び出しから経過した時間分のトークンをまとめて補充し(遅延補充)、足りていれば 1 つ消費して True を返します。実行すると最初の 5 回はバーストとして通り、続く 3 回は拒否され、1.1 秒待つと再び 2 回通ります。時間は逆戻りしない time.monotonic() で測ります。
token_bucket.py
import time
class TokenBucket:
"""Allow bursts of up to `capacity` requests, refilled at `rate` tokens per second."""
def __init__(self, rate: float, capacity: float) -> None:
self.rate = rate
self.capacity = capacity
self.tokens = capacity
self.updated = time.monotonic()
def allow(self, cost: float = 1.0) -> bool:
now = time.monotonic()
self.tokens = min(self.capacity, self.tokens + (now - self.updated) * self.rate)
self.updated = now
if self.tokens >= cost:
self.tokens -= cost
return True
return False
if __name__ == "__main__":
bucket = TokenBucket(rate=2, capacity=5) # 2 requests per second, bursts of 5
print([bucket.allow() for _ in range(8)]) # 5 x True, then 3 x False
time.sleep(1.1) # about 2.2 tokens come back
print(bucket.allow(), bucket.allow(), bucket.allow()) # True True False
python token_bucket.pyインストールから レート制限 の中心となる考え方まで、6 章で順を追って学びます。
レート制限 について質問し、経験を共有し、意見を交わす場所です。
まだディスカッションはありません。最初の話題を始めましょう。
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。