PHP APIの利用制限はサービスの可用性とコストを守りますが、設計を誤ると正規の連携を妨げるおそれがあります。適切に設計するには、1分あたりのリクエスト数を決めるだけでは不十分です。誰が利用し、どの操作を実行し、どのリソースが危険にさらされ、実際のトラフィックがどう振る舞うかを把握する必要があります。
効果的な設計には、利用パターンに適した制限、インスタンス間で一貫性のあるカウンター、利用者が復旧できるレスポンスが必要です。また、特に複数のクライアントが同じ認証情報を共有する場合や、共通リソースに依存する場合は、ルールを厳格化する前にその影響を観察する必要があります。
レート、クォータ、同時実行数を区別する

これらの制御はそれぞれ異なる問題から保護するもので、相互に置き換えられるものではありません。
- リクエストレート:短い時間間隔に受け付けるリクエスト数を制限します。急増するトラフィックや、アプリケーションを飽和させる継続的なトラフィックの抑制に役立ちます。
- 累積クォータ:1日あたり、または請求サイクルあたりの操作数など、より長い期間における総使用量を制限します。契約上の利用量や、累積するとコストの高い処理を管理するのに役立ちます。
- 同時実行数:同時に実行できる操作数を制限します。各操作が長時間にわたってワーカー、接続、その他のリソースを占有する場合に有効です。
クライアントがレートを守っていても、長時間の操作を多数同時に実行することがあります。また、リクエスト数が少なくても、コストの高い日次クォータを消費する場合があります。低減したいリスクに基づいて制御方法を決め、複数の制御が必要なら、それらの相互作用と適用順序を明確にしてください。
制限対象のIDとリソースを決める
制限キーは、運用上意味のある消費単位を表す必要があります。製品によっては、認証情報、ユーザー、組織、クライアントアプリケーション、ルート、またはそれらの組み合わせが対象になります。IPアドレスだけを基準にすると、共有ネットワーク上の利用者に不利益を与える可能性があり、認証済みの利用者を適切に区別できません。匿名トラフィックやセキュリティ制御では、IPアドレスを補助的なシグナルとして利用できます。
認証済みクライアントについては、安定したIDにポリシーを紐付け、組織間の分離を適用するのが適切です。複数のシステムで認証情報を共有すると、急増を引き起こしたシステムを特定しにくくなる場合があります。可能であれば認証情報を分けるか、消費量を個別に追跡できる属性を追加してください。未加工のシークレットをカウンターキーやログに含めないでください。
すべてのルートのコストが同じとは限りません。単純なクエリと大規模なエクスポートに、必ずしも同じ予算を割り当てる必要はありません。基準が利用者にとって理解しやすく、一貫していることを前提に、コストの高い操作に異なる重みやポリシーを設定できます。サービス側の制限も確認してください。APIへのリクエストが少なくても、データベースや外部プロバイダーなどの共有依存先を飽和させる可能性があります。
利用パターンに合った時間枠を選ぶ
固定ウィンドウは説明が簡単ですが、ある期間の終わりに発生した急増に続いて、次の期間の開始直後にも急増を許すことがあります。スライディングウィンドウは保存と計算の負荷が増える代わりに、この影響を抑えられます。トークン方式では、一定範囲のバーストを許容しながら平均レートを制御できます。正規のトラフィックが波状に到着する場合に有効です。どの方式を選ぶかは、利用パターンと必要な精度によって決まります。
正規の活動ピークを不正利用と混同しないでください。スケジュールされた処理、業務開始時の同期、障害後の再試行によって、リクエストが集中することがあります。製品でバーストを許容する場合は、その規模と予算が回復するまでの時間を明示してください。長時間の操作については、同時実行数も制限するか、希少なリソースを占有する前に受付を制御してください。
クライアントの再試行も重要です。一時的なレスポンスを受けて直ちに再試行すると、制限によってピークがさらに悪化することがあります。ランダムな揺らぎを加えた段階的なバックオフを推奨し、同じ冪等性キーで繰り返された操作を新規リクエストとして数えるのか、安全な再送として扱うのかを定義してください。
PHPを複数インスタンスで実行する場合にカウンターを連携させる
プロセスのメモリだけに保存したカウンターは、単一インスタンスでは機能することがありますが、複数インスタンスにトラフィックを分散すると一貫性が失われます。各サーバーが制限の一部をそれぞれ受け付け、全体では上限を超える可能性があります。複数インスタンスのデプロイでは、適切なアトミック操作を備えた共有ストア、または同等の仕組みを使って状態を連携させる必要があります。
カウンターシステムの障害時にどう動作するかも設計してください。システムが利用できなくなったとき、すべてのリクエストを拒否すれば正規のクライアントを妨げる可能性があり、すべて受け付ければ重要な依存先を危険にさらすおそれがあります。判断はルートのリスクによって異なります。影響の小さいクエリと、高額なコストを発生させる操作とで、異なる障害時の挙動を選ぶのが妥当な場合もあります。判断基準を文書化し、性能低下を警告してください。
組織やルートを混在させるほど汎用的なカウンターキーや、消費量全体の管理を難しくするほど細分化されたキーは避けてください。一時的なキーが際限なく蓄積しないよう、状態の有効期限とクリーンアップを定義してください。設定変更によってカウンターが予期せずリセットされたり、重複したりしないことも確認します。
拒否をAPI契約の一部として伝える
制限に達した場合は、API契約に沿った一貫性のあるHTTPステータスを返します。レート制限では通常、429 Too Many Requestsを使い、内部情報を明かさずに制限の種類を示す構造化された本文を返します。別の理由で操作を拒否した場合に、このステータスを誤解を招く形で使わないでください。
再試行できる推定時刻や、契約で定められた制限値・使用量など、復旧に役立つ情報を含めてください。Retry-Afterを送る場合は、有効な待機時間を示していることを確認します。ルート間でレスポンスを一貫させ、他のクライアントのカウンターを公開しないでください。利用者が一時的な拒否を、認証、検証、可用性に関するエラーと区別できる必要があります。
影響を観察し、根拠に基づいて調整する
受け付けたリクエストと拒否したリクエスト、IDやクライアントセグメント(安全な方法で扱うこと)、ルート、適用したポリシー、理由を記録します。レイテンシ、同時実行数、関連する依存先への負荷も測定してください。認証情報や不要な個人情報は保存せず、分析に十分な場合は保護または集計した識別子を使います。
拒否の増加だけでは、しきい値が厳しすぎるとは判断できません。影響を受けたクライアント、時間帯、ルート、操作時間、その後の再試行など、パターンを調べてください。共有認証情報を使う組織やスケジュールされたタスクに拒否が集中するなど、誤検知の兆候を調査します。一度に変更する変数は一つにし、変更をロールバックできる手段を確保してください。
ポリシーを段階的に導入する

制限を有効にする前に、利用データを使ってポリシーを評価し、代表的なシナリオをテストしてください。アーキテクチャ上可能であれば、ブロックせずに拒否されたはずのリクエストを記録します。この観察は負荷テストの代わりにはならず、過去のデータがあらゆるピークを予測できることを保証するものでもありません。
- 制御したいリスクと、レート、クォータ、同時実行数、またはそれらの組み合わせのどれが適切かを定義する。
- IDとリソースごとに制限を割り当て、ユーザー間・組織間の分離を検証する。
- バースト、低速な操作、再試行、共有認証情報、カウンターストアの障害をテストする。
- 複数インスタンスで制限が連携して適用され、一時状態がクリーンアップされることを確認する。
- 拒否レスポンス、再試行の案内、現在の利用者との互換性を検証する。
- 拒否、レイテンシ、依存先を監視し、連携に影響する可能性のある変更を告知する。
PHP APIの利用制限は、プラットフォームとクライアントの継続利用の両方を守る必要があります。最善のポリシーは最も厳しいものではなく、誰の利用かを特定できるルール、予測可能なレスポンス、望ましくない影響を修正するのに十分な根拠によってリスクを制御できるものです。



