APIM ポリシー rate-limit と rate-limit-by-key の挙動調査

Pocket

はじめに

普段のお仕事では「API 周りの面倒事アレコレ」を Azure API Management を使って解消しています。

その際に調査した内容について、ネタになるのでは?と思ったのでこちらの記事で共有いたします。

アクセスを制限するポリシー

API Management では APIに対するポリシーをXMLとして定義することで「APIへのアクセス制限」や「APIから返ってきたレスポンス加工」といった機能を付与できます。

個人的に 最も頻繁に 使われるのでは…?と思うのが rate-limit, rate-limit-by-key といった 「回数」でアクセスを制限するポリシー です。
(似たようなポリシーに quota, quota-by-key というポリシーがありますが、こちらは「容量」によるアクセス制限です)

rate-limit

  • 公式ドキュメント:
  • 要点:
    • サブスクリプション単位で アクセス回数制限します
    • 「回数」や「制限解除までの秒数」が指定できます
    • アクセス制限に引っかかると 429 Too Many Requests を返します
  • ポリシー例:

    「サブスクリプションキーごとに3コールまで許可、5秒後に制限が解除される」の意味

    <policies>
        <inbound>
            <base />
            <rate-limit calls="3" renewal-period="5" />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>
    

rate-limit-by-key

  • 公式ドキュメント:
  • 要点:
    • 任意のキーで アクセス回数制限します
    • 「回数」や「制限解除までの秒数」が指定できます(他にも計上する条件も指定できます)
    • アクセス制限に引っかかると 429 Too Many Requests を返します
  • ポリシー例:

    「IPアドレスごとに3コールまで許可、5秒後に制限が解除される」の意味

    <policies>
        <inbound>
            <base />
            <rate-limit-by-key calls="3" renewal-period="5" counter-key="@(context.Request.IpAddress)" />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>
    

疑問

もっともシンプルな利用ケースとしては、「サブスクリプションキーごとに利用可能な回数を設ける」といったものかと思います。
では、以下の2つのポリシーは同じ挙動を示すのでしょうか?

<inbound>
    <base />
    <rate-limit-by-key calls="3" renewal-period="5" counter-key="@(context.Subscription.Id)" />
</inbound>
<inbound>
    <base />
    <rate-limit calls="3" renewal-period="5" />
</inbound>

実際に実験してみました。

実験手順

  1. 製品を一つ作り、製品に紐付いたサブスクリプションキーを発行する
    • 例: Sample という製品を作成して、サブスクリプションキーを発行
      01
  2. 以下のAPIを作る
    • rate-limit-3
      • rate-limit ポリシーで calls=3 とする
    • rate-limit-5
      • rate-limit ポリシーで calls=5 とする
    • rate-limit-by-key-3
      • rate-limit-by-key ポリシーで calls=3 とする
    • rate-limit-by-key-5
      • rate-limit-by-key ポリシーで calls=5 とする
    • ※ オペレーションは以下だけ追加しておく(最低限、APIとして叩けるようにする)
      • メソッド:GET
      • オペレーション名:op
      • パス:/
    • All operations に対して、ポリシーを記述する
    • renewal-period10 秒としておく
    • ※ すべてのAPIを 1. で作成した製品に紐づけておく
    • ※ すべて同一のサブスクリプションキーでAPIを叩く
      02
  3. JMeter で以下の様なジョブを作成する
    • はじめに rate-limit-3rate-limit-510回ずつ 交互に叩く
    • 余裕を持って 15秒待つ(下図の 2つ目のスレッドグループ設定に注意!)
      • スケジューラ にチェックを入れ
      • 起動遅延15 とし、
      • 持続時間は 100 としておく
    • つぎに rate-limit-by-key-3rate-limit-by-key-510回ずつ 交互に叩く
      03
  4. JMeter を実行し、結果を確認する

結果

以下の通りとなりました。

同じような、サブスクリプション別アクセス回数制限ポリシーを設定しても、挙動が微妙に異なるようです。

04

rate-limit の挙動

  • まずはじめに上画像の左側に注目します。3, 5, 3, 5, ・・・ と交互にAPIが叩かれる中、
  • 7件目、3回制限のAPIの4回目のリクエストで × 429 Too many requestsとなりました。
    • これは 3回制限をかけているので、4回目はアウトとなる、期待した通りの動作ですね。
    • 以降、すべて 3回制限の方は × となっています
  • 12件目、5回制限APIの6回目のリクエストで × 429 Too many requestsとなりました。
    • こちらも同様に、5回制限なので6回目以降はアウトになる、期待通りの動作ですね。
  • rate-limit に関しては、同一サブスクリプションキーを利用していても API別にリクエスト数が計上 され、ポリシーに設定した通りの回数で制限してくれるようです。

rate-limit-by-key の counter-key属性にサブスクリプションキーを指定した場合の挙動

  • 上画像の右側に注目します。「rate-limit-by-key-3 にリクエスト」から数えて、
  • 5件目、3回制限のAPIの3回目のリクエストですでに × 429 Too many requestsとなってしまいました
  • 8件目、5回制限のAPIの4回目のリクエストですでに × 429 Too many requestsとなってしまいました
  • 上記結果は、ポリシーを設定した側の感覚として とても違和感のある挙動 です。
  • ・・・が、同一サブスクリプションキーを使用していること を思い出しますと、以下の考えに行き着きました。
    • rate-limit-by-key では、純粋に counter-key に与えられた文字列だけで比較し
    • 同一サブスクリプションキーを使用している場合は、API別にリクエスト数を計上せず、サブスクリプション別で計上しているのでは?
  • 1件ずつ紐解いていくと・・・
    • 4件目:サブスクリプションキー単位で すでに リクエスト数は4件 となっている
    • 5件目:3回制限のAPI → API単位では 3件目だが、サブスクリプションキー単位では すでに 4件なので ×
    • 6件目:サブスクリプションキー単位で リクエスト数は 6件
    • 7件目:サブスクリプションキー単位で リクエスト数は 7件
    • 8件目:5回制限のAPI → API単位では 4件目だが、サブスクリプションキー単位では すでに 8件なので ×

まとめ

前提条件

  • 同一サブスクリプションキーを使用します
  • 同一製品上のAPIを叩きます

rate-limit

  • API単位でリクエスト数を計上する
  • ポリシーに書いた回数制限通りの動作をしてくれる
  • → サブスクリプションキーで制限をかけたい場合はこちらが誤解なく使えて便利?

rate-limit-by-keycounter-key にサブスクリプションキーを指定

  • サブスクリプション単位でリクエスト数を計上する
  • ポリシーに書いた回数制限と異なる動作をすることもあるので注意!
    • (仕組み的には おそらく期待通りの動作なのですが、ポリシーを使う側の人間からすると、期待と違う動作となります)

所感

  • このような細かい挙動は、公式ドキュメントとしても載せきれないのが現状です。
  • そのため、実際にポリシーを利用する場合には 余裕を持って事前に検証する のが吉です!
Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です