Anti-Pattern: Kontingentrichtlinie wiederverwenden

Sie lesen gerade die Dokumentation zu Apigee und Apigee Hybrid.
Apigee Edge-Dokumentation aufrufen.

Apigee bietet die Möglichkeit, die Anzahl der zulässigen Anfragen für einen API-Proxy für einen bestimmten Zeitraum mithilfe der Kontingentrichtlinie zu konfigurieren.

Anti-Pattern

Beim Wiederverwenden einer Kontingentrichtlinie wird der Kontingentzähler bei jeder Ausführung der Kontingentrichtlinie verringert, unabhängig davon, wo Kontingent verbraucht wird. Wird also eine Kontingentrichtlinie wiederverwendet:

  • innerhalb desselben Ablaufs oder verschiedener Abläufe eines API-Proxys
  • in verschiedenen Zielendpunkten eines API-Proxys

wird der Kontingentzähler bei jeder Ausführung verringert und es kommt viel früher als für die bestimmte Zeitspanne angenommen zu Fehlern infolge eines Kontingentverstoßes.

Das folgende Beispiel veranschaulicht, wie dies funktioniert.

API-Proxy

Nehmen wir an, wir haben einen API-Proxy namens „TestTargetServerQuota“, der den Traffic auf Basis des Ressourcenpfads an zwei verschiedene Zielserver weiterleitet. Außerdem möchten wir den API-Traffic auf 10 Anfragen pro Minute pro Zielserver beschränken. Dieses Szenario wird durch folgende Tabelle dargestellt:

Ressourcenpfad Zielserver Kontingent
/target-us target-US.somedomain.com 10 Anfragen pro Minute
/target-eu target-EU.somedomain.com 10 Anfragen pro Minute

Kontingentrichtlinie

Da das Traffic-Kontingent für beide Zielserver identisch ist, definieren wir eine einzelne Kontingentrichtlinie mit dem Namen „Quota-Minute-Target-Server“, wie unten dargestellt:

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

Zielendpunkte

Im Beispiel des Preflows des Zielendpunkts „Target-US“ verwenden wir die Kontingentrichtlinie „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>

Dieselbe Kontingentrichtlinie „Quota-Minute-Target-Server“ verwenden wir im Preflow des anderen Zielendpunkts „Target-EU“:

<!-- /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>

Muster für eingehenden Traffic

Nehmen wir an, wir erhalten in den ersten 30 Sekunden insgesamt 10 API-Anfragen für diesen API-Proxy im folgenden Muster:

Ressourcenpfad /target-us /target-eu Alle
Anzahl der Anfragen 4 6 10

Etwas später erhalten wir die elfte API-Anfrage mit dem Ressourcenpfad als /target-us, beispielsweise nach 32 Sekunden.

Wir gehen unter der Annahme, dass wir nach zulässigem Kontingent noch sechs API-Anfragen für den Zielendpunkt target-us haben, davon aus, dass die Anfrage erfolgreich ausgeführt wird.

Tatsächlich erhalten wir jedoch diesen Fehler: Quota violation error.

Grund: Weil wir für beide Zielendpunkte dieselbe Kontingentrichtlinie verwenden, dient zum Erfassen der API-Anfragen an beiden Zielendpunkten ein einzelner Kontingentzähler. Entsprechend erschöpfen wir das Kontingent von 10 Anfragen pro Minute aggregiert und nicht für den einzelnen Zielendpunkt aus.

Auswirkungen

Dieses Anti-Pattern kann zu einer bedeutenden Abweichung führen und zu der Annahme, dass die Kontingentlimits zu schnell aufgebraucht wurden.

Best Practice

  • Verwenden Sie das Element <Class> oder <Identifier>, um mehrere eindeutige Zähler durch die Definition einer einzigen Kontingentrichtlinie zu verwalten. Nun definieren wir die im vorherigen Abschnitt erläuterte Kontingentrichtlinie „Quota-Minute-Target-Server“, wobei wir wie unten gezeigt den Header target_id als <Identifier> verwenden:
    <!-- /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>
    
    • Diese Kontingentrichtlinie werden wir weiter wie zuvor in den Zielendpunkten „Target-US“ und „Target-EU“ verwenden.
    • Nehmen wir Folgendes an: Wenn der Header target_id den Wert „US“ hat, werden die Anfragen an den Zielendpunkt „Target-US“ weitergeleitet.
    • Hat der Header target_id den Wert „EU“, werden die Anfragen an den Zielendpunkt „Target-EU“ weitergeleitet.
    • Auch wenn wir für beide Zielendpunkte dieselbe Kontingentrichtlinie verwenden, werden separate Kontingentzähler auf Grundlage des Werts <Identifier> verwaltet.
    • Mit dem Element <Identifier> können wir entsprechend dafür sorgen, dass jeder der Zielendpunkte das zulässige Kontingent von 10 Anfragen erhält.
  • Verwenden Sie in jedem der Abläufe/Zielendpunkte/API-Proxys separate Kontingentrichtlinien, um immer die zulässige Anzahl von API-Anfragen zu erhalten. Sehen wir uns nun das im obigen Abschnitt verwendete Beispiel an, um einzuschätzen, wie wir das zulässige Kontingent von 10 Anfragen für jeden der Zielendpunkte erreichen können.
    • Definieren Sie je eine separate Kontingentrichtlinie für die Zielendpunkte „Target-US“ und „Target-EU“.

      Kontingentrichtlinie für den Zielendpunkt „Target-US“:

      <!-- /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>
      

      Kontingentrichtlinie für den Zielendpunkt „Target-EU“:

      <!-- /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>
      
    • Verwenden Sie die entsprechende Kontingentrichtlinie in der Definition der Zielendpunkte, wie unten dargestellt:

      Zielendpunkt „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>
      

      Zielendpunkt „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>
      
    • Da wir jeweils eine separate Kontingentrichtlinie für die Zielendpunkte „Target-US“ und „Target-EU“ verwenden, wird ein separater Zähler verwaltet. Dadurch wird sichergestellt, dass wir für jeden der Zielendpunkte das zulässige Kontingent von 10 API-Anfragen pro Minute erhalten.
  • Verwenden Sie das Element <Class> oder <Identifier>, um mehrere eindeutige Zähler zu verwalten.