アンチパターン: Quota ポリシーの再利用

Apigee Edge の Quota ポリシーを使用すると、一定期間内に API プロキシに送信できるリクエストの数を構成できます。

アンチパターン

Quota ポリシーが再利用されると、使用される場所に関係なく、Quota ポリシーが実行されるたびに割り当てカウンタが減少します。つまり、Quota ポリシーが以下のどちらで再利用された場合でも減少します。

  • 1 つの API プロキシの同じフロー内または異なるフロー内
  • 1 つの API プロキシの異なるターゲット エンドポイント

こうして、実行されるたびに割り当てカウンタが減少し、指定された時間間隔で予想されるよりもはるかに早く割り当て違反エラーが発生します。

次の例を使用して、これがどのように機能するかを説明しましょう。

API プロキシ

「TestTargetServerQuota」という名前の API プロキシがあるとします。これはリソースパスに基づいて 2 つの異なるターゲット サーバーにトラフィックをルーティングします。また、これらの各ターゲット サーバーの API トラフィックを 1 分あたり 10 リクエストに制限します。このシナリオをまとめた表を以下に示します。

リソースパス ターゲット サーバー 割り当て
/target-us target-US.somedomain.com 1 分あたり 10 リクエスト
/target-eu target-EU.somedomain.com 1 分あたり 10 リクエスト

割り当てポリシー

トラフィック割り当ては両方のターゲット サーバーで同じであるため、以下に示すように「Quota-Minute-Target-Server」という名前の単一の Quota ポリシーを定義します。

<!-- /antipatterns/examples/1-8.xml -->
<Quota name="Quota-Minute-Target-Server">
  <Interval>1</Interval>
  <TimeUnit>minute</TimeUnit>
  <Distributed>true</Distributed>
  <Allow count="10"/>
</Quota>

ターゲット エンドポイント

ターゲット エンドポイント「Target-US」のプリフローで Quota ポリシー「Quota-Minute-Target-Server」を使用してみましょう。

<!-- /antipatterns/examples/1-9.xml -->
<TargetEndpoint name="Target-US">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>Quota-Minute-Target-Server</Name>
      </Step>
    </Request>
  </PreFlow>
  <HTTPTargetConnection>
    <URL>http://target-us.somedomain.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

また、他のターゲット エンドポイント「Target-EU」のプリフローでも同じ Quota ポリシー「Quota-Minute-Target-Server」を再利用します。

<!-- /antipatterns/examples/1-10.xml -->
<TargetEndpoint name="Target-EU">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <Name>Quota-Minute-Target-Server</Name>
      </Step>
    </Request>
  <Response/>
  </PreFlow>
  <HTTPTargetConnection>
    <URL>http://target-us.somedomain.com</URL>
  </HTTPTargetConnection>
</TargetEndpoint>

受信トラフィック パターン

次のパターンで、最初の 30 秒以内にこの API プロキシに対して合計 10 個の API リクエストを受け取ったとします。

リソースパス /target-us /target-eu 合計
リクエスト数 4 6 10

少ししてから、/target-us のリソースパスで 11 個目の API リクエストを受け取ります。これが 32 秒後だとします。

許可された割り当てに基づくと、ターゲット エンドポイント target-us ではまだ 6 個の API リクエストを受け取れるはずなので、リクエストは正常に処理されると想定できます。

しかし実際には、Quota violation error を受け取ります。

理由: 両方のターゲット エンドポイントで同じ Quota ポリシーを使用しているので、両方のターゲット エンドポイントに到達する API リクエストを追跡するために、単一の割り当てカウンタを使用しています。そのため、それぞれのターゲット エンドポイントではなく、両方のターゲット ポイントで合計して 1 分あたり 10 のリクエスト割り当てを使い切っています。

影響

このアンチパターンにより、期待とまったく一致しない状況が生じ、割り当て上限を早く使い切ったと感じさせることになります。

ベスト プラクティス

  • <Class> または <Identifier> 要素を使用して単一の Quota ポリシーを定義することにより、複数の一意のカウンタが維持されるようにします。前のセクションで説明した Quota ポリシー「Quota-Minute-Target-Server」を再定義しましょう。以下に示すようにヘッダー target_id<Identifier> として使用します。
    <!-- /antipatterns/examples/1-11.xml -->
    <Quota name="Quota-Minute-Target-Server">
      <Interval>1</Interval>
      <TimeUnit>minute</TimeUnit>
      <Allow count="10"/>
      <Identifier ref="request.header.target_id"/>
      <Distributed>true</Distributed>
    </Quota>
    
    • 前と同様に、ターゲット エンドポイント「Target-US」と「Target-EU」の両方でこの Quota ポリシーを引き続き使用します。
    • ヘッダー target_id の値が「US」の場合、リクエストはターゲット エンドポイント「Target-US」にルーティングされます。
    • 同様に、ヘッダー target_id の値が「EU」の場合、リクエストはターゲット エンドポイント「Target-EU」にルーティングされます。
    • そのため、両方のターゲット エンドポイントで同じ Quota ポリシーを使用しても、<Identifier> 値に基づいて個別の割り当てカウンタが維持されます。
    • したがって、<Identifier> 要素を使用することにより、それぞれのターゲット エンドポイントが、許可された 10 リクエストの割り当てを確実に受け取れるようになります。
  • 各フロー / ターゲット エンドポイント / API プロキシで個別の Quota ポリシーを使用して、許可された数の API リクエストを常に受け取れるようにします。上記のセクションと同じ例を使用して、許可された 10 個のリクエスト割り当てをターゲット エンドポイントごとに実現する方法を見ていきましょう。
    • ターゲット エンドポイント「Target-US」と「Target-EU」に 1 つずつ、個別の Quota ポリシーを定義します。

      ターゲット エンドポイント「Target-US」の Quota ポリシー:

      <!-- /antipatterns/examples/1-12.xml -->
      <Quota name="Quota-Minute-Target-Server-US">
        <Interval>1</Interval>
        <TimeUnit>minute</TimeUnit>
        <Distributed>true</Distributed>
        <Allow count="10"/>
      </Quota>
      

      ターゲット エンドポイント「Target-EU」の Quota ポリシー:

      <!-- /antipatterns/examples/1-13.xml -->
      <Quota name="Quota-Minute-Target-Server-EU">
        <Interval>1</Interval>
        <TimeUnit>minute</TimeUnit>
        <Distributed>true</Distributed>
        <Allow count="10"/>
      </Quota>
      
    • 以下に示すように、ターゲット エンドポイントの定義でそれぞれの Quota ポリシーを使用します。

      ターゲット エンドポイント「Target-US」:

      <!-- /antipatterns/examples/1-14.xml -->
      <TargetEndpoint name="Target-US">
        <PreFlow name="PreFlow">
          <Request>
            <Step>
              <Name>Quota-Minute-Target-Server-US</Name>
            </Step>
          </Request>
          <Response/>
        </PreFlow>
        <HTTPTargetConnection>
          <URL>http://target-us.somedomain.com</URL>
        </HTTPTargetConnection>
      </TargetEndpoint>
      

      ターゲット エンドポイント「Target-EU」:

      <!-- /antipatterns/examples/1-15.xml -->
      <TargetEndpoint name="Target-EU">
        <PreFlow name="PreFlow">
          <Request>
            <Step>
              <Name>Quota-Minute-Target-Server-EU</Name>
            </Step>
          </Request>
          <Response/>
        </PreFlow>
        <HTTPTargetConnection>
          <URL>http://target-eu.somedomain.com</URL>
        </HTTPTargetConnection>
      </TargetEndpoint>
      
    • ターゲット エンドポイント「Target-US」と「Target-EU」で個別の Quota ポリシーを使用しているので、個別のカウンタが維持されます。これにより、それぞれのターゲット エンドポイントで、1 分あたり 10 の API リクエストという許可された割り当てを受け取ることができます。
  • <Class> または <Identifier> 要素を使用して、複数の一意のカウンタが維持されるようにします。