Antipadrão: reutilizar uma política de cotas

Esta é a documentação da Apigee e da Apigee híbrida.
Confira a documentação da Apigee Edge.

A Apigee permite configurar o número de solicitações permitidas de um proxy de API por um período específico usando a política de cotas.

Antipadrão

Se uma política de cotas for reutilizada, o contador de cotas será reduzido sempre que essa política for executada, independentemente do local de uso. Ou seja, se uma política de cota for reutilizada:

  • no mesmo fluxo ou em fluxos diferentes de um proxy de API;
  • em diferentes endpoints de destino de um proxy de API.

Em seguida, o contador será reduzido toda vez que for executado e acabará recebendo erros de violação de cota muito antes do esperado pelo intervalo de tempo especificado.

Utilizaremos o exemplo a seguir para explicar como isso funciona.

Proxy da API

Digamos que temos um proxy de API chamado "TestTargetServerQuota", que direciona o tráfego para dois servidores de destino diferentes com base no caminho do recurso. Além disso, queremos restringir o tráfego da API a 10 solicitações por minuto para cada um desses servidores de destino. Veja a tabela que descreve esse cenário:

Caminho do recurso Servidor de destino Cota
/target-us target-US.somedomain.com 10 solicitações por minuto
/target-eu target-EU.somedomain.com 10 solicitações por minuto

Política de cotas

Como a cota de tráfego é a mesma para os dois servidores de destino, definimos uma política de cota única chamada "Quota-Minute-Target-Server", conforme mostrado abaixo:

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

Endpoints de destino

Vamos usar a política de cotas "Quota-Minute-Target-Server" no pré-fluxo do endpoint de destino "Target-US":

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

Além disso, também vamos reutilizar a mesma política de cota "Quota-Minute-Target-Server" no pré-fluxo do outro endpoint de destino "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>

Padrão do tráfego de entrada

Vamos supor que temos um total de 10 solicitações de API para esse proxy de API nos primeiros 30 segundos com o seguinte padrão:

Caminho do recurso /target-us /target-eu Tudo
# solicitações 4 6 10

Pouco depois, recebemos a 11ª solicitação de API com o caminho do recurso como /target-us, por exemplo, após 32 segundos.

Esperamos que a solicitação seja bem-sucedida, supondo que ainda temos seis solicitações de API para o endpoint de destino target-us de acordo com a cota permitida.

Mas, na realidade, temos um Quota violation error.

Motivo: como estamos usando a mesma política de cota nos endpoints de destino, um contador de cotas único é usado para rastrear as solicitações de API que encontram esses endpoints. Assim, esgotamos a cota de 10 solicitações por minuto em vez de para o endpoint de destino individual.

Impacto

Esse antipadrão pode resultar em uma incompatibilidade fundamental nas expectativas, fazendo parecer que os limites da cota se esgotaram antes do tempo.

Prática recomendada

  • Use os elementos <Class> ou <Identifier> para garantir que vários contadores exclusivos sejam mantidos ao definir uma única política de cotas. Para redefinir a política de cotas "Quota-Minute-Target-Server" que acabamos de explicar na seção anterior, usaremos o cabeçalho target_id como <Identifier> para o exemplo abaixo:
    <!-- /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>
    • Continuaremos a usar essa política de cotas nos endpoints de destino "Target-US" e "Target-EU" como antes.
    • Agora, vamos supor que o cabeçalho target_id tenha um valor "US" e, em seguida, as solicitações sejam encaminhadas para o endpoint de destino "Target-US".
    • Da mesma forma, se o cabeçalho target_id tiver um valor "EU", as solicitações serão encaminhadas para o endpoint de destino "Target-EU".
    • Portanto, mesmo se usarmos a mesma política de cotas nos endpoints de destino, os contadores de cotas separados serão mantidos com base no valor de <Identifier>.
    • Assim, ao usar o elemento <Identifier>, podemos garantir que cada endpoint de destino receba a cota permitida de 10 solicitações.
  • Use a política de cotas separada em cada um dos fluxos/endpoints de destino/proxies de API para garantir que você sempre consiga a contagem de solicitações de API permitida. Agora vamos analisar o mesmo exemplo usado na seção acima para ver como é possível alcançar a cota permitida de 10 solicitações para cada um dos endpoints de destino.
    • Defina uma política de cotas separada, uma para os endpoints de destino "Target-US" e "Target-EU".

      Política de cotas para o endpoint de destino "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>

      Política de cotas para o endpoint de destino "Target-US":

      <!-- /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>
    • Use a respectiva política de cotas na definição dos endpoints de destino, conforme mostrado abaixo:

      Endpoint de destino "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>

      Endpoint de destino "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>
    • Como estamos usando a política de cotas separada nos endpoints de destino "Target-US" e "Target-EU", um contador separado será mantido. Isso garante o recebimento da cota permitida de 10 solicitações de API por minuto para cada um dos endpoints de destino.
  • Use os elementos <Class> ou <Identifier> para garantir que vários contadores exclusivos sejam mantidos.