AWS の API スロットリングの仕組み - トークンバケットアルゴリズムと 429 エラーの正体

AWS API のレート制限がトークンバケットアルゴリズムで実装されている仕組み、バーストキャパシティの概念、サービスごとの制限値の違い、スロットリング回避の実践的な対策を解説します。

なぜ AWS はすべての API にレート制限をかけるのか

AWS のすべての API には、アカウントごと・リージョンごとのレート制限 (スロットリング) が設定されています。制限を超えたときの応答はサービスによって系統が分かれ、大きく 3 通りあります。第 1 に、EC2 の API は RequestLimitExceeded を HTTP 503 (Service Unavailable) で返します。第 2 に、API Gateway は HTTP 429 (Too Many Requests) を返します。第 3 に、多くの AWS サービスの API は ThrottlingException を HTTP 400 (Bad Request) で返します。つまり「スロットリングは 429 で飛んでくる」と単純化すると、503 や 400 で返る系統を取りこぼします。リトライ判定は HTTP ステータスだけでなく、エラーコード (RequestLimitExceeded / ThrottlingException / TooManyRequestsException など) と併せて行うのが安全です。レート制限の目的は 2 つあります。第 1 に、マルチテナント環境の公平性の確保です。1 つのアカウントが API を大量に呼び出すと、同じインフラを共有する他のアカウントのパフォーマンスに影響します。レート制限は「ノイジーネイバー問題」を防ぐガードレールです。第 2 に、顧客自身の保護です。アプリケーションのバグで無限ループが発生し、API を毎秒数万回呼び出してしまうケースがあります。レート制限がなければ、この暴走が高額な請求につながります。レート制限は、意図しない暴走を早期に検出するセーフティネットとして機能します。サービスによっては、レート制限値を Service Quotas で可視化し、上限緩和リクエストで引き上げを申請できます。ただしすべてのサービス・すべての制限が一律に可視化・緩和できるわけではありません。EC2 の API スロットリング値のように、現在値の確認や引き上げ自体をリクエストしてアクセスを得る形の制限もあるため、設計時は「Service Quotas に出ていれば確認できる、出ていなければサポート経由で確認する」という二段構えで考えます。

トークンバケットアルゴリズムの仕組み

AWS の API スロットリングは、トークンバケットアルゴリズムで実装されています。このアルゴリズムは、バケツ (容器) にトークン (許可証) が一定速度で補充され、API リクエストごとにトークンを 1 つ消費する仕組みです。バケツが空になるとリクエストは拒否されます。実際の値で見てみます (以下は 2026 年 8 月時点の公式ドキュメント記載値で、アカウントやリージョンによって異なる場合があります)。EC2 の API スロットリングのドキュメントでは、フィルタもページネーションも伴わない非変更アクション (DescribeInstances など) のリクエストトークンバケットは最大容量 50 トークン・補充レート 10 トークン/秒、それ以外の標準的な非変更アクションは最大容量 100 トークン・補充レート 20 トークン/秒と示されています。DescribeInstances を例に取ると、バケツが満杯の状態からは瞬間的に 50 リクエストを送信できます (バースト)。使い切った後は補充レートに律速され、毎秒 10 リクエストのペースに落ち着きます。ここで押さえるべきは役割分担です。バケツの最大容量がバースト時に一気に出せる量を決め、補充レートが定常的に許されるレートを決めます。「バースト = 容量」「定常 = 補充レート」という対応を取り違えると、見積もりが数倍ずれます。バーストキャパシティは、短時間の急増を吸収するバッファです。アプリケーションの起動時に一斉に API を呼び出すようなパターンでは、この容量が効きます。逆に、長時間走り続けるバッチ処理では容量は最初の一瞬しか効かず、実効スループットは補充レートで決まります。

サービスごとに異なるスロットリングの粒度

スロットリングの粒度はサービスによって大きく異なります。EC2 の API は、API アクションごとに個別のレート制限が設定されています。DescribeInstances と RunInstances は別々のバケットで管理されるため、DescribeInstances のスロットリングが RunInstances に影響することはありません。さらに EC2 には、リクエストレート制限とは別軸の「リソースレート制限」があります。RunInstances のようにリソースを作成・変更するアクションは、リクエスト回数のバケットに加えてリソーストークンバケットを消費します。RunInstances の場合、リソーストークンバケットは最大容量 1000 トークン・補充レート 2 トークン/秒です (2026 年 8 月時点の公式ドキュメント記載値)。重要なのは、このバケットが API 呼び出し回数ではなく操作対象のリソース数に比例して減る点です。1 回の RunInstances で 100 インスタンスを起動すればリソーストークンを 100 消費するため、呼び出し回数が数回でもリソースレート制限側でスロットリングされ得ます。大量起動・大量削除を行う自動化では、この第 2 の軸を必ず見積もりに入れます。一方、DynamoDB のスロットリングはテーブルレベルで適用されます。テーブルのプロビジョンドキャパシティ (RCU/WCU) を超えるリクエストがスロットリングされます。これは API レベルのスロットリングとは異なり、データアクセスのスループット制限です。Lambda の同時実行数制限もスロットリングの一種です。アカウントの同時実行数の既定クォータは 1,000 ですが、新規に作成したアカウントは削減されたクォータで開始し、使用量に応じて AWS 側が自動的に引き上げます (2026 年 8 月時点の公式ドキュメント記載)。そのため「新しいアカウントでも最初から 1,000 まで出る」前提で設計すると、負荷試験で想定外のスロットリングに当たります。現在値は Service Quotas で確認するのが確実です。API Gateway は、アカウントレベルで秒間 10,000 リクエスト (デフォルト) のレート制限があり、さらに API ごと、ステージごと、メソッドごとに個別のスロットリング設定が可能です。この多層的なスロットリングにより、特定の API エンドポイントへの集中アクセスが他のエンドポイントに影響しないよう制御できます。

指数バックオフとジッター - SDK が自動で行うリトライ戦略

スロットリングエラーを受け取った場合の正しい対処は、指数バックオフ (Exponential Backoff) とジッター (Jitter) を組み合わせたリトライです。指数バックオフは、リトライ間隔を 1 秒、2 秒、4 秒、8 秒と指数的に増加させる戦略です。これにより、スロットリング中のサービスに対するリクエスト圧力を段階的に緩和します。ジッターは、リトライ間隔にランダムな揺らぎを加える手法です。指数バックオフだけでは、同時にスロットリングされた複数のクライアントが同じタイミングでリトライし、再びスロットリングされる「サンダリングハード」問題が発生します。ジッターを加えることで、リトライのタイミングが分散されます。AWS SDK はこのリトライ戦略を内部で自動的に実装しています。AWS SDK for JavaScript v3 の既定は「最大 3 試行」で、これは初回リクエスト 1 回 + リトライ最大 2 回という意味です。「リトライを 3 回する」と読み違えると、想定より 1 回多い試行回数で見積もってしまうので注意します。例外もあり、DynamoDB と DynamoDB Streams のクライアントは 4 試行・基本バックオフ 25 ミリ秒というより積極的な設定が用意されています (2026 年の新リトライ体系での値で、オプトイン設定から段階的に既定へ移行中です)。リトライの挙動は特定の言語だけの話ではなく、AWS SDK 共通の設定として standard / adaptive / legacy の 3 モードが定義されています。現行世代の SDK と CLI は standard が既定で、以前の legacy モードから移行しました。adaptive はクライアント側で送出レートを学習して絞り込むモードで、スロットリングが常態化している処理向けの選択肢です。そして standard / adaptive には「retry quota」と呼ばれる総量制御が入っています。これは SDK クライアントが内部に持つトークンバケットで、リトライのたびにトークンを消費し、リクエストが成功すると少しずつ回復します。トークンが枯渇した時点でリトライは打ち切られます。つまり本記事の主題であるトークンバケットは、サービス側のレート制限だけでなく、クライアント側がリトライを撒き散らさないための仕組みとしても使われているわけです。SDK を使わずに直接 API を呼び出す場合は、これらのリトライロジックを自前で実装する必要があります。

スロットリングを事前に回避する設計パターン

スロットリングが発生してからリトライするよりも、そもそもスロットリングを発生させない設計が理想です。第 1 のパターンは、API 呼び出しの削減です。EC2 の DescribeInstances を毎秒呼び出してインスタンスの状態を監視するのではなく、EventBridge のイベント (EC2 Instance State-change Notification) を使えば、状態変化があったときだけ通知を受け取れます。ポーリングからイベント駆動への転換は、API 呼び出し数を劇的に削減します。第 2 のパターンは、キャッシュの活用です。頻繁に変わらない情報 (アカウントの設定、リージョンの一覧など) は、ローカルにキャッシュして API 呼び出しを減らします。第 3 のパターンは、バッチ API の活用です。DynamoDB の BatchGetItem は、最大 100 個のアイテムを 1 回の API 呼び出しで取得できます。個別に GetItem を 100 回呼ぶよりも、API 呼び出し数を 99% 削減できます。S3 の ListObjectsV2 も、MaxKeys パラメータで 1 回のリクエストで最大 1,000 オブジェクトを取得できます。

参考資料 (AWS 公式)

本ページの一次情報は AWS 公式サイトおよび公式ドキュメントです。最新の仕様 / 料金は次の公式ページで確認できます。

本ページと公式ドキュメントの記述が食い違う場合は、公式ドキュメントを正としてください。