見出し画像

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

はじめに

普段のお仕事では「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 という製品を作成して、サブスクリプションキーを発行

  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-period は 10 秒としておく

    • ※ すべてのAPIを 1. で作成した製品に紐づけておく

    • ※ すべて同一のサブスクリプションキーでAPIを叩く

  3. JMeter で以下の様なジョブを作成する

    • はじめに rate-limit-3rate-limit-510回ずつ 交互に叩く

    • 余裕を持って 15秒待つ(下図の 2つ目のスレッドグループ設定に注意!)

      • スケジューラ にチェックを入れ

      • 起動遅延15 とし、

      • 持続時間は 100 としておく

    • つぎに rate-limit-by-key-3rate-limit-by-key-510回ずつ 交互に叩く

  4. JMeter を実行し、結果を確認する

01
01
02
02
03
03


結果

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

04
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-key で counter-key にサブスクリプションキーを指定


  • サブスクリプション単位でリクエスト数を計上する

  • ポリシーに書いた回数制限と異なる動作をすることもあるので注意!

    • (仕組み的には おそらく期待通りの動作なのですが、ポリシーを使う側の人間からすると、期待と違う動作となります)


所感


  • このような細かい挙動は、公式ドキュメントとしても載せきれないのが現状です。

  • そのため、実際にポリシーを利用する場合には 余裕を持って事前に検証する のが吉です!

この記事が気に入ったらサポートをしてみませんか?