Antipatrón: reutilizar una política de cuotas

Estás consultando la documentación de Apigee y Apigee Hybrid.
Consulta la documentación de Apigee Edge.

Apigee te permite configurar el número de solicitudes que se permiten en un proxy de API durante un periodo específico mediante la política de cuotas.

Antipatrón

Si reutilizas una política de cuotas, el contador de cuotas se reducirá cada vez que la ejecutes. Esto ocurrirá independientemente de en cuál de las siguientes situaciones se utilice:

  • En el mismo flujo o distintos flujos de un proxy de API
  • En diferentes puntos de conexión de destino de un proxy de API

Como los contadores de cuotas se reducirán cada vez que se ejecute la política, acabarás obteniendo errores de infracción de la cuota mucho antes de lo esperado en el periodo especificado.

Para explicar este proceso, nos serviremos del siguiente ejemplo:

Proxy de API

Supongamos que tenemos un proxy de API llamado "TestTargetServerQuota", que dirige el tráfico a dos servidores de destino diferentes en función de la ruta del recurso. Además, queremos limitar el tráfico de las API a 10 solicitudes por minuto en cada uno de esos servidores de destino. En la siguiente tabla se refleja esta situación hipotética:

Ruta del recurso Servidor de destino Cuota
/target-us target-US.somedomain.com 10 solicitudes por minuto
/target-eu target-EU.somedomain.com 10 solicitudes por minuto

Política de cuotas

Como la cuota de tráfico es la misma para ambos servidores de destino, definimos una política de cuota única llamada "Quota-Minute-Target-Server", tal y como se muestra a continuación:

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

Puntos de conexión de destino

Vamos a utilizar la política de cuota "Quota-Minute-Target-Server" en el flujo previo del punto de conexión 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>

Además, reutilizaremos esa misma política de cuota en el flujo previo del otro punto de conexión de destino, que es "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>

Patrón de tráfico entrante

Supongamos que tenemos un total de 10 solicitudes a la API para este proxy de API en los primeros 30 segundos con el siguiente patrón:

Ruta del recurso /target-us /target-eu Todo
# solicitudes 4 6 10

Poco después (digamos, por ejemplo, 32 segundos más tarde), recibimos la undécima solicitud a la API con la ruta del recurso como /target-us.

Contando con que todavía tenemos 6 solicitudes a la API en el punto de conexión de destino target-us de acuerdo con la cuota permitida, esperamos que la solicitud se complete correctamente.

Sin embargo, lo que obtenemos en realidad es Quota violation error.

Motivo: al haber utilizado la misma política de cuotas en ambos puntos de conexión de destino, se usa un solo contador de cuotas para hacer el seguimiento de las solicitudes a la API que se realizan en ambos puntos. Como consecuencia, se agota la cuota de 10 solicitudes por minuto de forma conjunta, en lugar de por cada punto de conexión de destino individual.

Impacto

Este antipatrón puede dar lugar a un desajuste fundamental de las expectativas, por lo que se interpreta como que los límites de cuota se han agotado prematuramente.

Práctica recomendada

  • Usa los elementos <Class> o <Identifier> para asegurarte de que se mantienen varios contadores únicos definiendo una sola política de cuotas. Vamos a modificar la política de cuotas "Quota-Minute-Target-Server" que hemos explicado en la sección anterior. Para ello, usa el encabezado target_id como <Identifier> tal y como se muestra a continuación:
    <!-- /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>
    • Seguiremos utilizando esta política de cuotas en los puntos de conexión de destino "Target-US" y "Target-EU" como antes.
    • Ahora bien, si el encabezado target_id tiene un valor "US", las solicitudes se enrutan al punto de conexión de destino "Target-US".
    • Del mismo modo, si el encabezado target_id tiene un valor "EU", las solicitudes se enrutan al punto de conexión de destino "Target-EU".
    • Por tanto, aunque se utilice la misma política de cuotas en ambos puntos de conexión de destino, se mantienen contadores de cuotas independientes en función del valor de <Identifier>.
    • Por esa razón, utilizando el elemento <Identifier>, podemos garantizar que cada punto de conexión de destino obtendrá la cuota permitida de 10 solicitudes.
  • Utiliza la política de cuotas independiente de cada uno de los flujos, puntos de conexión de destino o proxies de API para asegurarte de que siempre usas el número permitido de solicitudes a la API. A continuación, utilizaremos el mismo ejemplo de la sección anterior para ver cómo podemos conseguir la cuota permitida de 10 solicitudes por cada punto de conexión de destino.
    • Define una política de cuotas independiente, concretamente, una para cada punto de conexión de destino: "Target-US" y "Target-EU".

      Política de cuotas del punto de conexión 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 cuotas del punto de conexión de destino "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>
    • Usa la política de cuotas correspondiente en la definición de los puntos de conexión de destino, tal y como se muestra a continuación:

      Punto de conexión 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>

      Punto de conexión 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 vamos a usar una política de cuotas independiente para cada uno de estos puntos, se mantendrá también un contador independiente para ambos. De esta forma, se asegura la cuota permitida de 10 solicitudes a la API por minuto para cada punto de conexión de destino.
  • Usa los elementos <Class> o <Identifier> para cerciorarte de que hay varios contadores únicos.