server
WebAPI
api

WebAPIを設計するうえでの利用制限(Rate Limit)について調べた


経緯

APIを設計する時に「利用制限をどうすべきか」という議論が起きると思います。

とりあえず有名なAPIを調べて、傾向やビッグウェーブなどあればと思い調べました。

以下、各サービスのAPIドキュメントは2018年7月時点くらいに調べたものとなります。


結論(まとめ)

十人十色でした!!

言い換えると、共通のベストプラクティスという物は無さそうで

以下の2つの軸を元にサービスに応じてカスタマイズしていく形かなと考えます。


  1. 制限をかける粒度を選択 / 組み合わせる

    ・サービス(大きな機能)単位で制限

    ・機能に応じて何種類かの区分を作り制限

    ・APIエンドポイント単位で制限

    ・重要度に分けて制限

    ・認証の種類で制限


  2. 実行制限の枠(rate limit window)を決める

    制限を掛ける=リセットされるまでの、時間。


また、上記以外にもセットで現在の利用制限状況の表現方法を決める必要がありそうです。

特にリセットされるまでの表現について、後述で紹介するブログにも、非常に参考になる以下の記事にも記載がありますが、残り秒数にすべきという話があります。

参考:翻訳: WebAPI 設計のベストプラクティス


調べたAPIと結果

API制限といえばTwitterが有名かと思いますが、その他よく「イケてる」と耳にするAPIや、思いついたものを調べてみました。


  • GitHub

  • Google APIs

  • kintone

  • Twitter

  • Slack

  • Stripe


GitHub

制限時のHTTPステータス
参考URL

403 Forbidden
API Document


制限の一例


  • search以外は1時間あたり5000req

  • searchのみ1分30req(認証なしの場合は1分10req)


特徴


  • searchとそれ以外でざっくりと定義されている。

  • ただし、不正利用検知のようなロジックがあり、条件を満たすと同様に403を返すようになる(詳細のメッセージにその旨記載される)

  • HTTPレスポンスヘッダに制限状況が記載される。


Google APIs

制限時のHTTPステータス
参考URL

403 FORBIDDEN

API Document
※リンク先はYoutube Data API


制限の一例


  • ※クォータという概念で管理される。


特徴


  • 読み取りや書き取りなどリクエストによって消費されるクォータが異なる。

  • APIの種類ごとにクォータが設定されており、console より、[割り当て]から確認可能。


kintone

制限時のHTTPステータス
参考URL

記載なし(200以外)
API Document


制限の一例


  • APIによる同時接続数はドメインごとに100が上限。


特徴


  • X-ConcurrencyLimit-Limitとして同時接続数の上限値を返却

  • X-ConcurrencyLimit-Runningとして現在の同時接続数を返却


Twitter

制限時のHTTPステータス
参考URL

429 Too Many Requests

API Document1
API Document2
ヘルプセンター


制限の一例


  • 1日2400ツイート(※別途サービスに対しての制限もあり)。
    users/suggestions:15分あたり15回



特徴


  • 認証方法(ユーザー or アプリケーション)によってAPIエンドポイント単位で異なる制限が可能。

  • 投稿などはユーザー単位のみの制限が適用される。

  • HTTPレスポンスヘッダに当該APIの制限状況が記載される。

  • プレミアムプランだと制限は別(無し?)というマネタイズもあり。


Slack

制限時のHTTPステータス
参考URL

429 Too Many Requests
API Document


制限の一例


  • メッセージの投稿は1秒1回など

  • 他、Web API methodsは1分あたり1~100回



特徴


  • 制限の種類を5つのTierに分類し、APIごとにそのTierが指定されている。

  • Retry-Afterヘッダで「再試行可能までの秒数」を返す


Stripe

制限時のHTTPステータス
参考URL

429 - Too Many Requests

ブログ
API Document


制限の一例


  • ※具体的な閾値は言及なし


特徴


  • 4種類の制限方法を組み合わせている。


    • Request rate limiter(毎秒Nリクエストの制限)

    • Concurrent requests limiter(同時実行の制御)

    • Fleet usage load shedder(クリティカルなAPIの一定利用枠の確保)

    • Worker utilization load shedder(重要度の低い順からリクエストを切っていく)




上限到達エラー時のHTTPステータスコード

Twitter,Stripe,Slackが「429 Too Many Requests」を返し、

GitHub, Google APIsは「403 Forbidden」を返すのが特徴的です。

429はRFC6585に記載のあるやつですね。


現在の利用制限状況の表現方法

Twitter,GitHub, kintoneは独自のHTTPヘッダにて返します。

一方、今回調べた中ではSlackがrfc6585にも記載のあるRetry-Afterを用いています。

このあたりは2013年に言及された記事も見つけました。

HTTPヘッダにUNIX Timestampを入れるべきではないのか

なお独自のHTTPヘッダは、各サービスごとに名称と意味合いが若干異なっておりました。


Twitter

HTTPヘッダ名
説明

x-rate-limit-limit
そのエンドポイントの上限

x-rate-limit-remaining
ウィンドウ(15分)での残り要求可能数

x-rate-limit-reset
(※残り時間っぽい表現ですが、UNIX timeなのでリセット時刻では)


GitHub

HTTPヘッダ名
説明

X-RateLimit-Limit
1時間あたりに許可されるリクエストの最大数。

X-RateLimit-Remaining
ウィンドウでの残り要求可能数

X-RateLimit-Reset
ウィンドウでの制限がリセットされる時刻。


kintone

HTTPヘッダ名
説明

X-ConcurrencyLimit-Limit
同時接続数の上限値

X-ConcurrencyLimit-Running
現在の同時接続数


所感

個人的にはGitHubの「サービス単位でシンプルな制限を課しつつ、別途不正利用検知という層を入れる」のが面白いなと思いました。
また、今回、そんなに沢山のサービスを調べた訳では無いですが、「ほぼ被っている」APIが1つも無かったことに驚きました。

RFCがーは理解しつつも、実際問題「あと1週間使えません」という時にClientに604800を返すのは険しいのではとも思ったのですが、そうした使い方は不正利用へのペナルティが目的となるはずで、今回のような話とは別に考えることなのだろうと思いました。

パフォーマンス維持を目的とするならRetry-Afterで足りるよう設計できるよね、と言われるとそうだなと思います。