レート制限のないAPIは、あるクライアントが待機をいっさい入れないループを書いたその瞬間まで、見事に動きます。その後は一人の呼び出し元が全員の共有する処理能力を食いつぶし、他のすべての利用者で遅延が増え、障害は一本の暴走スクリプトではなくサービス全体の停止のように見えます。レート制限とは、この事態を一つのクライアントに限定された、小さく明確に名前のついたエラーへ変える仕組みです。
制限値を正しく決めるのは、ほとんど「明示する」ことに尽きます。何を数えるか、どの期間で、誰ごとに、そして超えたクライアントへ何を伝えるか。本ガイドではアルゴリズム、根拠をもって説明できる数値の決め方、よく書かれたクライアントが制限内にとどまるためのヘッダー、そして自分がクライアント側のときの減速方法を扱います。
レート制限が重要な理由
レート制限はたいてい障害の後に導入されますが、同時に4つの別々の問題を解きます。
- 処理能力の保護。サービスには持続可能な最大スループットがあります。制限は需要をその下に保ちます。運任せではなく設計として。
- 公平性。クライアント単位の制限がなければ、もっとも騒がしい呼び出し元が最も多くの資源を得ます。制限があれば、各クライアントは予測できる取り分を得ます。
- 費用の管理。 1リクエストごとにデータベース参照、外部API呼び出し、モデル実行が走るなら、無制限のAPIは無制限の請求書です。
- 不正利用への耐性。認証情報の総当たり、スクレイピング、列挙はいずれも量に依存します。制限はそれらを実用に耐えないほど遅くし、アラートを出せるほど目立たせます。
もう一つ、目立たない5つめの利点があります。文書化された制限は契約です。クライアントはそれを尊重するように書けます。上限に衝突して初めて知るよりずっと良い状態です。
知っておくべきアルゴリズム
どのリミッターも同じ問いに答えます。「このリクエストは今許されるか」。違いはバーストの扱いにあり、クライアントとして実際に感じ取るのもその違いです。
| アルゴリズム | バーストを許すか | 向いている用途 |
|---|---|---|
| トークンバケット | 許す。バケットの大きさまで | 公開API。通常の既定選択 |
| リーキーバケット | 許さない。出力は完全に一定 | 処理能力が固定のバックエンドの保護 |
| 固定ウィンドウ | 許すが、境界で不公平になる | 精度を求めない単純なクォータ |
| スライディングウィンドウ | 本来の制限内でのみ | 正確な適用。状態保持の費用は増える |
トークンバケット
決まった数のトークンが入り、一定の速さで補充されるバケツを想像してください。リクエストごとにトークンを1つ取り出します。空なら拒否します。2つの数値で完全に説明できます。補充レートは持続スループット、バケットの大きさは許容する最大のバーストです。
100トークンのバケットを毎秒10補充すると、待機していたクライアントはいきなり100リクエストを送れ、その後は毎秒10に落ち着きます。多くの場合これが望ましい挙動です。実際のクライアントは波があるため、短い急増は不正利用ではなく通常のトラフィックであり、長期の平均は上限内に収まります。トークンバケットが既定である理由は明確です。実装が安価で、クライアントごとにトークン数とタイムスタンプだけあればよく、挙動を文書で説明しやすいからです。
リーキーバケット
リーキーバケットはその鏡像です。リクエストはキューに入り、穴から漏れる水のように一定の速さで出ていきます。キューが満杯なら新しいリクエストは拒否されます。出力は完全に一定で、これはまったく急増を吸収できないバックエンド、たとえば旧来のシステムや再販している外部APIの前に置くときにこそ必要な性質です。
代償は遅延です。ほぼ満杯のキューに入ったリクエストは、速く失敗する代わりに待ちます。クライアントからは遅いサーバーとキュー待ちの区別がつきません。壊れやすいものへ向かうトラフィックを整えるには適しますが、自分の伸縮するサービスを守るならトークンバケットを選んでください。
固定ウィンドウとスライディングウィンドウ
固定ウィンドウは暦の期間ごとに数えます。たとえば毎時1,000件、毎時0分にリセット。カウンターとキーだけで実装できますが、よく知られた欠点があります。境界バーストです。10:59:59に1,000件、11:00:01にさらに1,000件を送るクライアントは、方針の中に収まったまま2秒間で2,000件を届けます。想定したピークの2倍です。
スライディングウィンドウは、現在の暦のブロックではなく直前の期間で数えることでこれを解決します。11:00:01でも10:59:59のリクエストを見ているため、超過分を拒否します。正確な実装はリクエストごとにタイムスタンプを保持するためメモリを使います。よく使われる妥協案は、前のウィンドウの件数を重なっている割合で加重するもので、状態をごく一部に抑えつつほぼすべてのAPIで十分な精度が得られます。
制限値の決め方
数値は測定から決めてください。寛大に見える切りのよい数字からではありません。うまくいく手順は次のとおりです。
- 上限を測る。遅延が悪化するまで負荷試験を行います。そのスループットから余裕を引いた値が実際の処理能力です。
- 想定する同時クライアント数で割る。これはクライアント単位の制限の出発点であり、最終的な答えではありません。
- 現在のトラフィックを見る。クライアントごとのリクエスト率の95パーセンタイルと99パーセンタイルを調べます。99パーセンタイルを下回る制限は、正当な利用者のせいで呼び出されることになります。
- バーストの余裕を加える。毎秒レートの10〜20倍程度がよく使われるバケットの大きさです。通常のページ読み込みを吸収しつつ、持続的な不正利用は許しません。
- 段階を設ける。匿名、認証済み、有料のクライアントが同じ制限を共有すべきではありません。上限を上げることに課金するのは、APIの価格設定としてもっとも素直な方法です。
- 適用の前に観察する。拒否を始める前に1週間、拒否されていたはずのリクエストを記録します。
何をキーに数えるかは、数値と同じくらい重要です。IP単位は匿名トラフィックで唯一の選択肢ですが、共有ネットワークやNATに不利に働きます。APIキー単位は公平で、認証済み呼び出しの正しい既定です。アカウント単位なら、キーを増やして能力を買い足すことを防げます。多くのAPIはこの3つを同時に使い、全体の制限、キーごとの制限、そして高コストな経路にはエンドポイントごとの制限を設けています。
数値が決まったあと、それをリクエスト間隔に直す計算はわずかに間違いやすいものです。レート制限計算ツールは制限値とウィンドウから、リクエスト間の最小間隔、安全な持続レート、公開できるRetry-Afterの値を算出します。
クライアントに必要なヘッダー
クライアントから見えない制限は、クライアントが衝突する制限です。状態は拒否時だけでなくすべてのレスポンスで送ってください。
RateLimit-Limit— 現在のウィンドウの上限。RateLimit-Remaining— その中で残っているリクエスト数。RateLimit-Reset— 枠が更新されるまでの秒数。Retry-After—429や503のとき、待つべき時間。秒数またはHTTP日付。
X-RateLimit-*という書き方はいまも広く使われており、問題なく機能します。上記の接頭辞なしの名前が標準化された形で、移行期に両方送っても損はありません。大切なのは値が存在し正確であることです。それによって、よくできたクライアントは自分で速度を調整し、429を一度も見ずにすみます。
拒否するときは429 Too Many Requestsを返してください。403や汎用の500は使わないことです。429は「リクエストは正しく、後なら成功する」とクライアントに伝えられる唯一のコードで、正しい再試行を導く唯一の信号です。HTTPステータスコードのリファレンスでは、関連するコードと各コードがクライアントに課すことを扱っています。
クライアントとして429を扱う
接続の反対側から見ると、規則は短く、そしてほぼ常に実装が足りていません。
Retry-Afterを尊重する。サーバーが待つ時間を示しているなら、その時間だけ待ちます。これ以上の根拠はどこにもありません。- 示されていなければ指数的に下げる。 1秒、2秒、4秒、8秒と上限まで待ちます。即座の再試行は、過負荷を自ら招いた殺到に変えます。
- ジッターを加える。各待機を数百ミリ秒の範囲でランダムにずらします。これがないと、同時に失敗したクライアントが同時に再試行し、バックオフの計画が散らすはずだったピークを再現してしまいます。
- 試行回数に上限を設ける。 3〜5回で打ち切り、失敗として報告します。無限の再試行は本物の障害を隠します。
- ヘッダーで自分の速度を調整する。
RateLimit-Remainingを読み、拒否される前に減速します。これが「動くクライアント」と「たいてい動くクライアント」の差です。 429以外の4xxは再試行しない。400や422は毎回同じように失敗します。問題はリクエストそのものにあるからです。
よくある間違い
429の代わりに403を返す。クライアントは403を恒久的と読んで止まるか、やみくもに再試行します。どちらも望ましくありません。Retry-Afterを省く。クライアントに推測を強いることになり、ありがちな推測は「今すぐ」です。- IPだけで制限する。 1つのNATアドレスの背後にあるオフィス全体が1クライアントになり、分散スクレイパーは1,000クライアントになります。
- すべてのエンドポイントを同じに数える。キャッシュからの読み取りと8秒かかるレポートが同じ1トークンであるべきではありません。高コストな経路には重みをつけるか、専用の制限を与えます。
- 厳しい制限と固定ウィンドウの組み合わせ。境界バーストにより、実際のピークは公開した数値の2倍になります。
- バーストの余裕がまったくない。完全に平坦な制限は通常のトラフィックを拒否します。実際のクライアントはまとまって来るからです。
- 文書化されていない制限。数値が文書にもヘッダーにもなければ、どの導入者も本番で初めて知ります。
- ジッターなしの再試行。同期した再試行は、短い急増を長く続くものに変えます。
自分の制限値を計算する
よいレート制限は退屈です。クライアントはヘッダーを見て速度を調整し、バーストは吸収され、不正利用は抑えられ、誰も気づきません。そこへ至る道は、ほとんど算術と、自分の本当の処理能力についての誠実さです。実際に支えられる制限値とウィンドウから始め、それをクライアントに必要な間隔とRetry-Afterに換算し、両方を公開し、制限に近づいた事例を記録して、「厳しすぎる制限」と「振る舞いの悪いクライアント」を見分けられるようにしてください。
関連ツールとガイド:
- レート制限計算ツール — 制限値とウィンドウを間隔・バースト量・
Retry-Afterに変換。 - HTTPステータスコード —
429や503などがクライアントに課すこと。 - HTTPステータスコード完全ガイド — すべてのレスポンスクラスを解説。
- DNSルックアップ — APIのトラフィックが実際に届くホストを確認。
よくある質問
公開APIの既定のレート制限はどれくらいが妥当ですか?⌄
1リクエストにかかる費用によるため、万能の数値はありません。読み取り中心のJSON APIでよく使われる出発点は、キーごとに毎時1,000リクエスト、バースト20〜60で、そこから自分のパーセンタイルに合わせて調整します。持続可能なスループットを測り、想定する同時クライアント数で割り、正当な利用者のせいで呼び出されないよう、制限は正常トラフィックの99パーセンタイルより上に保ってください。
トークンバケットとリーキーバケットの違いは何ですか?⌄
トークンバケットはバケットの大きさまでバーストを許し、その後は補充レートに落ち着きます。実際のクライアントはまとまって来るため、公開APIに合います。リーキーバケットはリクエストをキューに入れ一定の速さで解放するので出力は完全に一定ですが、速く失敗する代わりに待たせます。急増をまったく吸収できないバックエンドの前にはリーキーバケット、それ以外にはトークンバケットを使ってください。
固定ウィンドウはなぜ問題になるのですか?⌄
境界バーストのためです。あるウィンドウの終わり際に枠を使い切り、次のウィンドウの始まりでまた使い切るクライアントは、形式上は方針に収まりながら、数秒で想定ピークの2倍を届けます。スライディングウィンドウは直前の期間で数えるため、この挙動は正しく拒否されます。
レートリミッターはどのステータスコードを返すべきですか?⌄
429 Too Many RequestsとRetry-Afterヘッダーです。リクエストは正当で後なら成功するとクライアントに伝えられる唯一のコードであり、それが正しい再試行につながります。403は恒久的、500はサーバー側の不具合と読まれるため、どちらもクライアントを誤った振る舞いへ導きます。
クライアントは429をどう扱うべきですか?⌄
Retry-Afterがあればそれに従います。なければ指数的に下げ、1秒、2秒、4秒、8秒と待ち、各待機にランダムなジッターを加えて、同時に失敗したクライアントが同時に再試行しないようにします。試行は3〜5回で打ち切り、失敗を報告します。さらに良いのは、すべてのレスポンスでRateLimit-Remainingを読み、拒否される前に減速することです。
IPアドレス単位とAPIキー単位、どちらで制限すべきですか?⌄
認証済みトラフィックはAPIキー単位です。公平で、クライアントのネットワーク変更にも耐え、段階を設けられます。匿名リクエストではIPしか選べませんが、1つのNATアドレスの背後にあるオフィス全体を1クライアントとして扱い、分散スクレイパーを多数として扱ってしまいます。成熟したAPIはこの両方に加え、高コストな経路にはより厳しいエンドポイント単位の制限を設けています。
Web 開発とセキュリティに 15 年以上携わってきた実務経験を持つ。実践的な Web セキュリティ、つまりサイトを安全・確実に保ち、トラブルを素早く解決できるようにすることに注力。BuildToolForge は、こうしたチェックを無料で、プライベートに、わかりやすく行えるようにするためのサイトです。ツールは可能な限りブラウザ内で動作し、ツールに入力した内容は保存されません。
ガイドの書き方: すべてのガイドは実務経験をもとに執筆し、公式の標準と照らし合わせ、実際のドメインで自社ツールを使って検証しています。標準やツールが変わればガイドも更新します。誤りを見つけたら contact@buildtoolforge.com までお知らせください。