schedule2019-06-26

LaravelのAPIで429 Too Many Requestsが返る

負荷試験中にLaravelのAPIから429 Too Many Requestsが返るようになった。 当初、AWS EC2のt2.microの環境だったため負荷試験申請していないことが原因かと思い、はまってしまった。

原因を突き詰めると、Laravelのデフォルトでリクエスト数制限を掛ける処理になっているようです。

環境

  • php 7.3
  • Laravel 5.8

原因:ThrottleRequests

\app\Http\Kernel.phpにあるmiddlewareGroupsの設定に、API数を制限する記述があります。 'throttle:60,1'が同一のIPアドレスとドメインから1分間に60回までのリクエスト数に制限しています。

protected $middlewareGroups = [
        // 省略
        // 40行目付近
        'api' => [
            'throttle:60,1', // 1分間に60回まで
            'bindings',
        ],

throttleは$routeMiddleware`の中でvendorにあるモジュールを定義していました。

protected $routeMiddleware = [
        // 省略
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,

x-ratelimit-limit

throttleが有効になっている場合、HTTP Response Headersにx-ratelimit-limitx-ratelimit-remainingが付きます。

  • x-ratelimit-limit : リクエスト数上限
  • x-ratelimit-remainin : 残りのリクエスト数

ThrottleRequests - GitHubの処理

\Illuminate\Routing\Middleware\ThrottleRequests::class

リクエスト元は、IPアドレスとドメインのハッシュキーから識別しているようです。

protected function resolveRequestSignature($request)
    {
        if ($user = $request->user()) {
            return sha1($user->getAuthIdentifier());
        }
        if ($route = $request->route()) {
            // IPアドレスとドメインのハッシュ
            return sha1($route->getDomain().'|'.$request->ip()); 
        }
        throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
    }

また、RateLimiterというキャッシュストアを使ってリクエスト数をカウントしていました。

解消法

'throttle:60,1'の数値を緩和するか、この行を削除したら制限がなくなります。

参考

このコードは初めて見た。。。 AWSのAPI Gatewayでもよくみられるようです。

ThrottleRequestsについてたくさんの検証をされています。 日本語記事があって有難い。