冒頭まとめ

AWS の 429 Too Many Requests は「呼び出しすぎ」を示しますが、絞り込みを行った層によって、見えるエラーも対処も変わります。代表は3層です。第一に API Gateway で、レートとバーストの超過、または利用計画(usage plan)の割当量の超過で 429 を返します。第二に Lambda で、同時実行の枠が尽きると TooManyRequestsException(Rate exceeded)の 429 を返します。第三に、Lambda などのコードの中から呼び出している AWS の各サービス APIスロットリングで、こちらは SDK 上では 429 ではなく 400 の ThrottlingException 系として現れることもあります。

共通の第一手は、正しい再試行(ジッター付き指数バックオフ)です。ただし1つ重要な例外があります。利用計画の割当量(1日1万回など期間あたりの上限)を使い切った 429 は、待って再試行しても期間が切り替わるまで直りません。「再試行が効く429」か「割当が尽きた429」かの見極めが、最初の分岐になります。

エラーの概要

3層それぞれの典型的なエラーの形です。

API Gateway が絞り込んだ場合(レート超過、または割当超過):

{ "message": "Too Many Requests" }
{ "message": "Limit Exceeded" }

Lambda の同時実行が尽きた場合(呼び出し元に返るエラーの例。実際の報告の形式):

Rate Exceeded. (Service: AWSLambda; Status Code: 429;
Error Code: TooManyRequestsException; Request ID: ...)

コード内の AWS API が絞り込まれた場合(SDKエラー。この例では HTTP は 400):

An error occurred (ThrottlingException) when calling the <操作名> operation
(reached max retries: 4): Rate exceeded

3つ目のように、AWS のサービス APIスロットリングHTTP 429 とは限らず、400 の ThrottlingException や TooManyRequestsException として記録されることがあります(SDK の内部では retryable、つまり再試行してよいエラーとして扱われます)。「429」という数字だけを探すと見落とすため、Rate exceeded・Throttling という文言で探すのが確実です。

まず最初に:どの層が絞り込んだかを特定する

エラー文言と CloudWatch メトリクスで層を確定します。

応答が API Gateway の形式(Too Many Requests / Limit Exceeded)なら原因1です。利用計画を使っている場合は、どちらの文言かで「レート超過(再試行が効く)」か「割当超過(期間まで直らない)」かが分かれます。

Lambda が絡む構成では、公式の切り分けがそのまま使えます。対象の関数の Throttles メトリクス(絞られた呼び出しの数)を確認し、これが増えていれば関数の同時実行の枯渇(原因2)です。Throttles が増えていないのに Rate exceeded が出ている場合、絞られたのは関数ではなく、関数コードの中で呼んでいる AWS API です(原因3)。

よくある原因と解決手順

原因1:API Gateway のレート・バースト・割当の超過

公式ドキュメントのとおり、API Gateway の絞り込み設定は4層あります。リージョン全体に適用される AWS の上限、アカウント単位(リージョンごと)の上限、API のステージ・メソッド単位の設定、そして利用計画に紐づく API キークライアント)単位の設定です。定常レートとバーストを超えた瞬間の 429 は、ジッター付き指数バックオフでの再試行が公式の対処です。恒久対処としては、どの層の設定に当たったかを特定したうえで、ステージやメソッドの絞り込み値の見直し、応答のキャッシュによる呼び出し削減、アカウント単位のレート上限の Service Quotas での引き上げ申請(公式の注記どおり、バースト側の上限は調整できません)を検討します。

利用計画の割当量(期間あたりの総回数)を使い切った場合の 429(Limit Exceeded)は、性質が別です。再試行では解決せず、期間の切り替わりを待つか、割当量そのものを見直します。CloudWatch のアクセスログと利用計画の使用量画面で、どのキーがいつ使い切ったかを確認できます。

原因2:Lambda の同時実行の枠が尽きている

関数を同時に実行できる数には、アカウント(リージョン)全体の枠と、関数ごとに設定できる予約同時実行(reserved concurrency)があります。枠が尽きた状態の追加の呼び出しは TooManyRequestsException で拒否され、Throttles メトリクスに計上されます。

公式の確認手順は次のとおりです。まず ConcurrentExecutions メトリクス(最大値)と Throttles(合計)を見ます。予約同時実行を設定している関数なら、ConcurrentExecutions がその値に張り付いていないかを確認します。予約同時実行は他の関数から枠を守る保護であると同時に、その関数自身の上限にもなるため、値が小さすぎれば自分で自分を絞ります。特に 0 に設定された関数は一切のイベントを処理できません。予約同時実行を設定していない関数は非予約の共有枠を使うため、同じアカウントの別の関数が枠を食い尽くしていると、負荷の低い関数でも絞られます。関数の処理が遅い(メモリ不足で時間がかかる)ほど枠を長く占有するため、Max Memory Used と設定メモリの比較も公式の確認項目です。

もう1つ、呼び出し方式による挙動差を押さえておくと症状を読み違えません。同期呼び出し(応答を待つ形)の絞り込みは即座にエラーとして返り、再試行は呼び出し側の責任です。非同期呼び出し(イベントとして渡す形)の絞り込みは、イベントが内部の待ち行列に戻され、Lambda 自身が間隔を延ばしながら再試行します。同期の一括処理(Step Functions の並列実行や CLI からの連続 invoke)で 429 が出やすいのはこのためです。対処は、予約同時実行の適正化、遅い関数の改善、並列度の抑制、必要ならアカウントの同時実行クォータの引き上げ申請です。

原因3:コード内の AWS API 呼び出しが絞られている

関数の Throttles が増えていないのに Rate exceeded が出る場合、絞られたのはコードの中で呼んでいる AWSAPI(一覧取得や書き込みをループで大量に呼ぶ処理など)です。前述のとおり、この層のエラーは 400 の ThrottlingException として現れることもあります。

対処は再試行の正しい実装です。エラー直後の即時リトライは状況を悪化させるだけなので、ジッター付き指数バックオフ(待ち時間を毎回倍増させ、ばらつきを加える)で再試行します。AWS SDK には再試行の仕組みが組み込まれており、モードと最大試行回数を設定できます。

Before(失敗したら即座にリトライする):

import boto3
client = boto3.client("logs")
while True:
    try:
        client.put_log_events(...)
        break
    except Exception:
        continue  # 待たずに再試行 → 絞り込みを悪化させる

After(SDK の再試行設定に任せる):

import boto3
from botocore.config import Config

config = Config(retries={"max_attempts": 10, "mode": "standard"})
client = boto3.client("logs", config=config)
client.put_log_events(...)  # スロットリング時は SDK がバックオフ付きで再試行

再試行してもなお恒常的に絞られる場合は、呼び出し回数そのものの削減(一括系 API の利用、結果のキャッシュ、並列度の抑制)を行い、それでも足りない場合に限り、該当 API の TPS クォータの引き上げを Service Quotas で申請します(公式の注記どおり、すべてのクォータが調整可能なわけではありません)。

補足:429ではない類似エラー

同じ「呼び出しすぎ」でも、別のコードで返るサービスがあります。S3 のリクエストレート超過は 429 ではなく 503 Slow Down です(AWS の 503 エラー)。また、原因3で述べたとおり、多くのサービス APIスロットリングは 400 の ThrottlingException 系として現れます(コードは違っても、対処はこの記事の再試行の指針と同じです)。エラーの文言に Throttling や Rate exceeded が含まれていれば、HTTPコードにかかわらず絞り込みの問題として扱ってください。

切り分けの順序

  1. エラーの発生源を特定する。API Gateway の応答形式なら原因1、Lambda の TooManyRequestsException なら原因2、関数の Throttles が増えていないのに Rate exceeded ならコード内の API(原因3)。
  2. 原因1で利用計画を使っている場合、レート超過(再試行が効く)か割当超過(Limit Exceeded。期間まで直らない)かを文言と使用量で確定する。
  3. 再試行の実装を確認する。即時リトライをやめ、ジッター付き指数バックオフSDK の再試行設定)に置き換える。
  4. 恒久対処として、呼び出し削減(キャッシュ・一括化・並列度の抑制)、Lambda の予約同時実行と処理速度の見直し、必要な層のクォータ引き上げ申請を行う。

確認コマンド集

# 1. Lambda の絞り込み回数を確認(増えていなければ原因はコード内のAPI)
aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda --metric-name Throttles \
  --dimensions Name=FunctionName,Value=<関数名> \
  --start-time <開始時刻> --end-time <終了時刻> \
  --period 300 --statistics Sum

# 2. 関数の予約同時実行の設定を確認
aws lambda get-function-concurrency --function-name <関数名>

# 3. API Gateway の利用計画と割当・レート設定を確認
aws apigateway get-usage-plans

# 4. 対象クォータの現在値を確認(例: Lambda の同時実行数)
aws service-quotas get-service-quota \
  --service-code lambda --quota-code L-B99A9384

Editor’s Note

原因1の割当超過の実例として、AWS 公式フォーラム re:Post の報告があります(429 - Too Many Requests、2021年)。社内向けの API が突然 429 を返し始め、しばらくは一部のクライアントだけ動いていたものの、やがてすべての呼び出しが失敗したという報告です。報告者自身が原因を突き止めて共有しており、正体は API Gateway の利用計画に設定されていた月5,000回の割当量への到達でした。ログを見ると前日の夕方、5分間で1,000回を超える呼び出しが記録されており、想定外の大量呼び出しが月の割当を一気に使い切った形です。社内 API だったため、対処は月間割当の撤廃でした。再試行しても直らない 429 に出会ったら割当を疑う、そして割当に当たったときは「何がそんなに呼んだのか」までログで確認する、という2つの教訓がそのまま読み取れる記録です。

AWS の 429 は、絞り込んだ層(API Gateway・Lambda・個々のサービス API)と、絞り込みの種類(瞬間のレートか、期間の割当か)の掛け合わせで対処が決まります。闇雲に上限を上げる前に、どの層の何に当たったのかをメトリクスと文言で確定することが確実な近道です。


免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。