【ITニュース解説】API Rate Limiting: What Actually Breaks When You Get It Wrong
2026年09月14日に「Dev.to」が公開したITニュース「API Rate Limiting: What Actually Breaks When You Get It Wrong」について初心者にもわかりやすく解説しています。
ITニュース概要
APIのレートリミットは単なる回数制限では不十分。リクエストの種類や瞬間的な集中、複数サーバーでのカウント方法を考慮しないと、システムが過負荷になる。安定運用には、トークンバケット方式や中央集権的なカウンター、適切なエラー応答の実装が重要だ。
ITニュース解説
APIは、アプリケーション同士が情報をやり取りするための窓口のようなものであり、多くの利用者に使われることでその価値を発揮する。しかし、この窓口に対して一度に大量のアクセスが集中したり、悪意のある利用者が繰り返しアクセスしたりすると、システムに大きな負担がかかり、場合によってはサービス全体が停止してしまう恐れがある。APIレート制限とは、このような過剰なアクセスからシステムを保護し、全ての利用者が安定してサービスを利用できるよう、APIへのリクエスト数に上限を設ける仕組みのことである。
多くのチームは、システムに問題が発生した後で、後付けのようにレート制限を導入することが多い。例えば、プログラムがAPIをひたすら叩き続けたり、悪意のあるスクレイパーがデータを大量に取得しようとしたり、一人の利用者の誤操作が他の全ての利用者のリソースを奪ったりする、といった状況である。このような場合、緊急対応として「1分間に100リクエストまで」といった単純な制限を設けがちだが、このアプローチには多くの問題がある。
まず、APIリクエストの「コスト」は一律ではない。例えば、データベースから簡単な情報を取得するリクエストと、複数のデータベーステーブルを結合して複雑な検索を行うリクエストでは、システムにかかる負荷が大きく異なる。単純なリクエスト数のみで制限をかけると、軽いリクエスト100回と重いリクエスト100回が同じ扱いになり、システムは簡単に過負荷に陥ってしまう。また、リクエストは常に一定の間隔で送られてくるわけではない。例えば、ウェブページのダッシュボードを読み込む際に、同時に複数の情報を表示するために、短時間で10個以上のリクエストがまとめて送られ、その後はしばらくアクセスがない、といった「バースト(一時的な集中)」はごく普通の挙動である。単純な制限では、このような正当なバーストアクセスも制限の対象となり、利用者の体験を損なう可能性がある。さらに、「固定ウィンドウ」と呼ばれる方式、例えば「毎分0秒にリセットされる」制限では、問題が発生しやすい。例えば、「1分間に100リクエスト」という制限の場合、ある利用者が59秒に100リクエストを送り、次の1分が始まった直後の1秒にさらに100リクエストを送ると、わずか2秒の間に200リクエストが処理されることになる。これは「ルール上は問題ない」が、システムにとっては短期間での極端な負荷となり、脆弱性を生む。
では、どのような方法がより効果的なレート制限を実現するのか。いくつかの改善策がある。一つ目は、リクエストをカウントするアルゴリズムの改善である。「スライディングウィンドウ」や「トークンバケット」と呼ばれるアルゴリズムがこれにあたる。固定ウィンドウのように厳密な時間でリセットするのではなく、例えばトークンバケット方式では、一定量の「トークン(引換券)」が常に補充され、APIリクエストごとにこのトークンを消費する。トークンがなくなればリクエストは制限されるが、トークンが補充される速さによって平均的なリクエスト数を維持しつつ、一時的なバーストアクセスも自然に許容できるようになる。これは実際の利用状況に非常によく合致する。
二つ目は、「リクエスト数」だけでなく、「コスト」に基づいた制限を導入することである。先述の通り、リクエストの種類によってシステムにかかる負荷は異なる。そこで、データベースへの書き込みや複雑な計算を伴うリクエストには高い「コスト」を設定し、簡単なデータ読み出しには低い「コスト」を設定するなど、エンドポイントごとに重み付けを行う。これにより、少数の高コストなリクエストが大量の低コストなリクエストよりも大きなシステム負荷を引き起こすことを防ぎ、限られたリソースをより公平かつ効率的に配分できる。
三つ目は、利用者の認証状態に応じて異なる制限を設けることである。例えば、ログインしていない匿名ユーザーや、IPアドレスのみで識別されるトラフィックには、ログイン済みの認証されたユーザーよりも厳しめの制限を適用する。これにより、悪意のあるスクレイピングなどによる過剰なアクセスを防ぎつつ、同じオフィス内の複数の利用者が同じIPアドレスを使うことで、意図せず制限にかかってしまうといった問題を回避できる。
四つ目は、レート制限がかかった際に、クライアントに対して適切な情報を提供することである。単に「429 Too Many Requests」というエラーコードを返すだけでは、クライアントはいつ再試行すれば安全なのかを判断できない。そこで、APIのレスポンスヘッダーに「Retry-After」(いつ再試行可能か)、「X-RateLimit-Limit」(制限の上限)、「X-RateLimit-Remaining」(残りリクエスト数)、「X-RateLimit-Reset」(制限がリセットされるまでの時間)といった情報を含めるべきである。これらの情報をクライアントが利用することで、リトライ処理が無限ループに陥ることを防ぎ、システムにさらなる負荷をかけることなく、適切なタイミングでアクセスを再開できるようになる。
ここまで説明した改善策も重要だが、レート制限で最も大きな被害を引き起こす間違いは、複数のサーバーで動いているシステムにおいて、その制限が正しく「分散」されていないことである。現代の多くのシステムは、負荷分散のために複数のサーバーインスタンス(サーバーの複製)で構成されている。もし、それぞれのサーバーインスタンスが独立してリクエスト数をカウントしているとどうなるか。例えば、「1分間に100リクエスト」という制限を設けても、サーバーが3台あれば、クライアントはそれぞれのサーバーに100リクエストずつ、合計300リクエストを送ることができてしまう。これは実質的に「100リクエスト × サーバー数」の制限になってしまい、トラフィックが急増した際には、裏側にあるデータベースや他の共有リソースが過負荷で停止してしまうことになる。
この問題の解決策は、「カウンターを中央集約」することである。具体的には、Redisのような専用のインメモリデータベース(高速にデータを読み書きできるメモリ上のデータベース)を使って、全てのリクエストカウントを一元的に管理する。どのサーバーインスタンスからAPIリクエストが来ても、必ず中央のRedisにアクセスしてカウントをチェックし、制限に達していないかを確認する。これにより、全体として統一された制限を強制することが可能となる。この方法では、リクエストごとにわずかな追加の遅延(レイテンシ)が発生するが、レート制限が実際に機能するかどうかを決定づける重要な違いである。
もし、既存のAPIにレート制限を後付けで導入する場合、以下のような手順で進めることが推奨される。まず、すぐに制限をかけるのではなく、ログの収集とモニタリングから始める。現在のAPIが実際にどのようなトラフィックパターンで利用されているのかを正確に把握することで、現実的な制限値を設定できるようになる。次に、IPアドレスではなく、ログイン済みの認証されたクライアントごとに制限を設定する。これにより、より公平で、利用者にとって不便のない制限を実現できる。そして、固定ウィンドウではなく、トークンバケットやスライディングウィンドウといった、より柔軟なアルゴリズムを採用する。複数のサーバーインスタンスでAPIが動いている場合は、レート制限のカウンターを必ず中央集約する。レート制限がかかった際には、クライアントに対して429エラーコードとともに、適切なヘッダー情報(Retry-Afterなど)を返すようにする。最後に、常に制限値の近くでリクエストを送り続けているクライアントがいないか、アラートを設定して監視する。これは悪意のある行為ではなく、クライアント側のプログラムのバグである可能性も高いため、早期に発見し対処することが重要である。
レート制限は、適切に機能している間は利用者にその存在を意識させないものだが、一度問題が発生すると、システム全体に深刻な影響を及ぼし、その障害は非常に目に見えやすい。システムエンジニアにとって、APIのレート制限は、単なる「数字の設定」ではなく、システム全体の安定稼働とセキュリティを守るための重要な設計要素の一つである。基本的な原則を早期に正しく理解し、実践することで、後になって起こり得る多くの生産システムにおける障害を防ぐことができる。